functions framework c# entity-framework-4 user-defined-functions

functions - Llamando a la función escalar desde c#usando Entity Framework 4.0/.edmx



linq functions (4)

Me gustaría asignar mi función escalar a mi .edmx pero falla. Hago clic con el botón derecho en la asignación del marco de mi entidad y elijo el modelo de actualización de la base de datos. Aparece en mi carpeta de procedimientos almacenados en mi navegador modelo.

Sin embargo, cuando quiero agregarlo a mi carpeta de Function Imports en el navegador modelo, la función escalar de mensajes no aparece en la lista desplegable. ¿Alguien me puede ayudar?

Puedo llamar a la función escalar usando la forma antigua, como:

dbContext.ExecuteStoreQuery<DateTime?>( "SELECT dbo.getMinActualLoadDate ({0}, {1}, {2}) AS MyResult", LoadPkid, LoadFkStartLoc, TripSheetPkid).First();

Pero no es la mejor manera. Mi administrador desea que encuentre la manera de colocar la función escalar en la carpeta "función de importación" para poder llamar a la función escalar utilizando el siguiente código en lugar del código anterior:

dbContext.ExecuteFunction("getMinActualLoadDate ", paramList);

Intenté agregar una imagen para mostrar lo que quiero decir, pero como mi reputación sigue siendo baja, no puedo hacerlo. Sin embargo, la imagen se puede encontrar aquí: http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/756865e5-ff25-4f5f-aad8-fed9d741c05d

Gracias.


Aquí está mi solución a este problema, que es casi exactamente lo que su gerente estaba pidiendo ... aunque con 18 meses de retraso.

Como método de vainilla:

/// <summary> /// Calls a given Sql function and returns a singular value /// </summary> /// <param name="db">Current DbContext instance</param> /// <typeparam name="T">CLR Type</typeparam> /// <param name="sql">Sql function</param> /// <param name="parameters">Sql function parameters</param> /// <param name="schema">Owning schema</param> /// <returns>Value of T</returns> public T SqlScalarResult<T>(DbContext db, string sql, SqlParameter[] parameters, string schema = "dbo") { if (string.IsNullOrEmpty(sql)) { throw new ArgumentException("function"); } if (parameters == null || parameters.Length == 0) { throw new ArgumentException("parameters"); } if (string.IsNullOrEmpty(schema)) { throw new ArgumentException("schema"); } string cmdText = $@"SELECT {schema}.{sql}({string.Join(",", parameters.Select(p => "@" + p.ParameterName).ToList())});"; // ReSharper disable once CoVariantArrayConversion return db.Database.SqlQuery<T>(cmdText, parameters).FirstOrDefault(); } }

Y como método de extensión a EF:

namespace System.Data.Entity { public static class DatabaseExtensions { /// <summary> /// Calls a given Sql function and returns a singular value /// </summary> /// <param name="db">Current DbContext instance</param> /// <typeparam name="T">CLR Type</typeparam> /// <param name="sql">Sql function</param> /// <param name="parameters">Sql function parameters</param> /// <param name="schema">Owning schema</param> /// <returns>Value of T</returns> public static T SqlScalarResult<T>(this Database db, string sql, SqlParameter[] parameters, string schema = "dbo") { if (string.IsNullOrEmpty(sql)) { throw new ArgumentException("sql"); } if (parameters == null || parameters.Length == 0) { throw new ArgumentException("parameters"); } if (string.IsNullOrEmpty(schema)) { throw new ArgumentException("schema"); } string cmdText = $@"SELECT {schema}.{sql}({string.Join(",", parameters.Select(p => "@" + p.ParameterName).ToList())});"; // ReSharper disable once CoVariantArrayConversion return db.SqlQuery<T>(cmdText, parameters).FirstOrDefault(); } } }

Aunque no se fuma aquí, sugeriría pruebas de unidad antes de cualquier uso serio.


La única solución es convertir el tipo escalar de función en valor de tabla con un solo valor en la tabla, consulte el ejemplo de código.

No tiene que cambiar nada en el XML de EDMX, modifique la función SQL

Función escalar como estaba, que no funciona

CREATE FUNCTION [dbo].[GetSha256] ( -- Add the parameters for the function here @str nvarchar(max) ) RETURNS VARBINARY(32) AS BEGIN RETURN ( SELECT * FROM HASHBYTES(''SHA2_256'', @str) AS HASH256 ); END -- this doesn''t work.

Función escalar -> Convertida a la función de valor de tabla, funciona

CREATE FUNCTION [dbo].[GetSha2561] ( -- Add the parameters for the function here @str nvarchar(max) ) RETURNS @returnList TABLE (CODE varbinary(32)) AS BEGIN INSERT INTO @returnList SELECT HASHBYTES(''SHA2_256'', @str); RETURN; -- This one works like a charm. END

Edmx captura de pantalla


Me he encontrado con el mismo problema. Y aquí hay una solución que me ha parecido bastante adecuada (probada en EF5, pero también debería funcionar en EF4):

No se admiten funciones de asignación de valores escalares fuera de la caja, pero puede ejecutarlas directamente.

También puede editar el archivo edmx para que edmx genere el método adecuado para la función de valor escalar, pero se eliminará si sincroniza su modelo con la base de datos.

Escriba usted mismo la implementación de la función de valor escalar:

string sqlQuery = "SELECT [dbo].[CountMeals] ({0})"; Object[] parameters = { 1 }; int activityCount = db.Database.SqlQuery<int>(sqlQuery, parameters).FirstOrDefault();

O edite edmx y agregue Xml para el mapeo personalizado de la función de valor escalar:

<Function Name="CountActivities" Aggregate="false" BuiltIn="false" NiladicFunction="false" IsComposable="false" ParameterTypeSemantics="AllowImplicitConversion" Schema="dbo"> <CommandText> SELECT [dbo].[CountActivities] (@personId) </CommandText> <Parameter Name="personId" Type="int" Mode="In" /> </Function>

Esta información fue encontrada en esta publicación de blog.


Supongo que se pierde el cuadro de diálogo Edit Function Import , donde puede generar tipos complejos . tratar de explorar

Si ha creado correctamente los scalars , ahora puede navegar de esta manera

using (var con = new DatabaseEntities()) { long? invoiceNo = con.sp_GetInvoiceMaxNumber(code.Length + 2).First(); .... }