web-dev-qa-db-fra.com

Appel de la fonction scalaire à partir de c # à l'aide d'Entity Framework 4.0 / .edmx

Je voudrais mapper ma fonction scalaire à mon .edmx mais cela échoue. Je fais un clic droit sur le mappage de la structure de mon entité et je choisis le modèle de mise à jour dans la base de données. Il apparaît dans mon dossier de procédures stockées dans mon navigateur de modèles.

Cependant, quand je veux l'ajouter à mon Function Imports dossier dans le navigateur de modèles, le message la fonction scalaire n'apparaît pas apparaît dans la liste déroulante. Est-ce que quelqu'un peut m'aider?

Je peux appeler la fonction scalaire en utilisant l'ancienne méthode, comme:

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

mais ce n'est pas la meilleure façon. Mon responsable aimerait que je trouve un moyen de mettre la fonction scalaire dans le dossier "import de fonction" afin que je puisse appeler la fonction scalaire en utilisant le code suivant au lieu du code précédent:

dbContext.ExecuteFunction("getMinActualLoadDate ", paramList);

J'ai essayé d'ajouter une image pour montrer ce que je veux dire mais comme ma réputation est encore faible, je ne peux pas le faire. Cependant, l'image peut être trouvée ici: http://social.msdn.Microsoft.com/Forums/en-US/adodotnetentityframework/thread/756865e5-ff25-4f5f-aad8-fed9d741c05d

Merci.

21
jay

J'ai rencontré le même problème. Et voici la solution que j'ai trouvée suffisamment adaptée (testée dans EF5, mais devrait également fonctionner dans EF4):

La prise en charge des fonctions de valeur scalaire n'est pas prise en charge, mais vous pouvez les exécuter directement.

Vous pouvez également modifier le fichier edmx pour que edmx génère la méthode appropriée pour la fonction de valeur scalaire, mais il sera supprimé si vous synchronisez votre modèle avec la base de données.

Ecrivez vous-même l'implémentation d'une fonction à valeur scalaire:

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

Ou modifiez edmx et ajoutez Xml pour une cartographie personnalisée de la fonction à valeur scalaire:

<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>

Cette information a été trouvée dans ce article de blog

15
Pavel Luzhetskiy

Voici ma solution à ce problème, qui correspond presque exactement à ce que votre manager demandait .. quoique 18 mois de retard.

Comme méthode à la vanille:

    /// <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();

    }

}

Et comme méthode d'extension à 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();

        }

    }

}

Bien qu'il ne fume pas ici, je suggère des tests unitaires avant toute utilisation sérieuse.

7
dperish

La seule et la seule solution consiste à convertir le type scalaire de fonction en type de valeur de table avec une seule valeur dans le tableau, veuillez consulter l'exemple de code.

Vous n'avez rien à changer dans le XML EDMX, veuillez modifier la fonction SQL

Fonction scalaire telle qu'elle était, ce qui ne fonctionne pas

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.

Fonction scalaire -> Fonction convertie en valeur de table, cela fonctionne

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

Capture d'écran Edmx

enter image description here

1
Md. Alim Ul Karim

Je suppose que vous manquez le Edit Function Import boîte de dialogue, où vous pouvez générer Types complexes . essayez d'explorer.

enter image description here

Si vous avez réussi à créer le scalars, vous pouvez maintenant naviguer comme ceci

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

Code dans la page:

protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        using (MayEntities context = new MayEntities())
        {
            string str = context.Database.SqlQuery<string>("select dbo.HeyYou()").Single().ToString();
            Response.Write(str); //output:'Hey this works'
        }
    }
}

fonction scalaire:

CREATE FUNCTION [dbo].[HeyYou] ()
RETURNS varchar(20)
AS
BEGIN
    RETURN 'Hey this works'
END
go
0
sachin