web-dev-qa-db-fra.com

Comment appeler des procédures stockées avec EntityFramework?

J'ai généré un modèle EF4 à partir d'une base de données MySQL et j'ai inclus à la fois StoredProcedures et Tables.

Je sais comment effectuer des opérations instert/update/fetch/delete régulières sur l'EF, mais je ne trouve pas mes procédures stockées.

C'était ce que j'espérais: 

using (Entities context = new Entities())
{
    context.MyStoreadProcedure(Parameters); 
}

Modifier 1: 

Voici à quoi cela ressemblait sans EF: 

sqlStr = "CALL updateGame(?,?,?,?,?,?,?)";

commandObj = new OdbcCommand(sqlStr, mainConnection);
commandObj.Parameters.Add("@id,", OdbcType.Int).Value = inGame.id;
commandObj.Parameters.Add("@name", OdbcType.VarChar, 255).Value = inGame.name;
commandObj.Parameters.Add("@description", OdbcType.Text).Value = ""; //inGame.description;
commandObj.Parameters.Add("@yearPublished", OdbcType.DateTime).Value = inGame.yearPublished;
commandObj.Parameters.Add("@minPlayers", OdbcType.Int).Value = inGame.minPlayers;
commandObj.Parameters.Add("@maxPlayers", OdbcType.Int).Value = inGame.maxPlayers;
commandObj.Parameters.Add("@playingTime", OdbcType.VarChar, 127).Value = inGame.playingTime;    

return Convert.ToInt32(executeScaler(commandObj));

PS. Je peux changer la version EF si nécessaire

Modifier 1: 

CREATE DEFINER=`106228`@`%` PROCEDURE `updateGame`(
    inId INT,
    inName VARCHAR(255),
    inDescription TEXT,
    inYearPublished DATETIME,
    inMinPlayers INT,
    inMaxPlayers INT,
    inPlayingTime VARCHAR(127)
)
32
Ivy

Une solution consiste à utiliser la propriété Database du DbContext:

SqlParameter param1 = new SqlParameter("@firstName", "Frank");
SqlParameter  param2 = new SqlParameter("@lastName", "Borland");
context.Database.ExecuteSqlCommand("sp_MyStoredProc @firstName, @lastName", 
                              param1, param2);

EF5 soutient définitivement cela.

61
Quinton Bernhardt

Vous avez utilisé la fonction SqlQuery et indiqué l'entité pour mapper le résultat.

J'envoie un exemple pour effectuer ceci:

var oficio= new SqlParameter
{
    ParameterName = "pOficio",
    Value = "0001"
};

using (var dc = new PCMContext())
{
    return dc.Database
             .SqlQuery<ProyectoReporte>("exec SP_GET_REPORTE @pOficio",
                                        oficio)
             .ToList();
}
9
user2997069

Une fois votre procédure stockée importée dans votre modèle, vous pouvez cliquer dessus avec le bouton droit de la souris (à partir du navigateur de modèles, dans la section Context.Store/Stored Procedures), puis cliquer sur Add Function Import. Si vous avez besoin d'un type complexe, vous pouvez le créer ici. 

4
ESG

En gros, il vous suffit de mapper la procédure sur l'entité à l'aide du mappage de procédures stockées.

Une fois mappé, vous utilisez la méthode habituelle pour ajouter un élément dans EF et il utilisera votre procédure stockée à la place.

S'il vous plaît voir: Ce lien pour une procédure pas à pas . Le résultat sera l'ajout d'une entité comme so (qui utilisera réellement votre procédure stockée)

using (var ctx = new SchoolDBEntities())
        {
            Student stud = new Student();
            stud.StudentName = "New sp student";
            stud.StandardId = 262;

            ctx.Students.Add(stud);
            ctx.SaveChanges();
        }
1
Dave

Basé sur la requête initiale de l'OP pour pouvoir appeler un proc stocké comme ceci ...

using (Entities context = new Entities())
{
    context.MyStoreadProcedure(Parameters); 
}

Passager sans âme a un projet qui vous permet d’appeler un proc stocké depuis un cadre de travail comme celui-ci ....

using (testentities te = new testentities())
{
    //-------------------------------------------------------------
    // Simple stored proc
    //-------------------------------------------------------------
    var parms1 = new testone() { inparm = "abcd" };
    var results1 = te.CallStoredProc<testone>(te.testoneproc, parms1);
    var r1 = results1.ToList<TestOneResultSet>();
}

... et je travaille sur un framework de procédures stockées ( ici ) que vous pouvez appeler comme dans l'une de mes méthodes de test ci-dessous ...

[TestClass]
public class TenantDataBasedTests : BaseIntegrationTest
{
    [TestMethod]
    public void GetTenantForName_ReturnsOneRecord()
    {
        // ARRANGE
        const int expectedCount = 1;
        const string expectedName = "Me";

        // Build the paraemeters object
        var parameters = new GetTenantForTenantNameParameters
        {
            TenantName = expectedName
        };

        // get an instance of the stored procedure passing the parameters
        var procedure = new GetTenantForTenantNameProcedure(parameters);

        // Initialise the procedure name and schema from procedure attributes
        procedure.InitializeFromAttributes();

        // Add some tenants to context so we have something for the procedure to return!
        AddTenentsToContext(Context);

        // ACT
        // Get the results by calling the stored procedure from the context extention method 
        var results = Context.ExecuteStoredProcedure(procedure);

        // ASSERT
        Assert.AreEqual(expectedCount, results.Count);
    }
}

internal class GetTenantForTenantNameParameters
{
    [Name("TenantName")]
    [Size(100)]
    [ParameterDbType(SqlDbType.VarChar)]
    public string TenantName { get; set; }
}

[Schema("app")]
[Name("Tenant_GetForTenantName")]
internal class GetTenantForTenantNameProcedure
    : StoredProcedureBase<TenantResultRow, GetTenantForTenantNameParameters>
{
    public GetTenantForTenantNameProcedure(
        GetTenantForTenantNameParameters parameters)
        : base(parameters)
    {
    }
}

Si l'une ou l'autre de ces deux approches est-elle bonne?

1
Dib

C'est ce que j'ai récemment fait pour mon application de visualisation de données qui dispose d'une base de données SQL 2008 Dans cet exemple, je reçois une liste renvoyée par une procédure stockée:

public List<CumulativeInstrumentsDataRow> GetCumulativeInstrumentLogs(RunLogFilter filter)
    {
        EFDbContext db = new EFDbContext();
        if (filter.SystemFullName == string.Empty)
        {
            filter.SystemFullName = null;
        }
        if (filter.Reconciled == null)
        {
            filter.Reconciled = 1;
        }
        string sql = GetRunLogFilterSQLString("[dbo].[rm_sp_GetCumulativeInstrumentLogs]", filter);
        return db.Database.SqlQuery<CumulativeInstrumentsDataRow>(sql).ToList();
    }

Et puis cette méthode d'extension pour un formatage dans mon cas:

public string GetRunLogFilterSQLString(string procedureName, RunLogFilter filter)
        {
            return string.Format("EXEC {0} {1},{2}, {3}, {4}", procedureName, filter.SystemFullName == null ? "null" : "\'" + filter.SystemFullName + "\'", filter.MinimumDate == null ? "null" : "\'" + filter.MinimumDate.Value + "\'", filter.MaximumDate == null ? "null" : "\'" + filter.MaximumDate.Value + "\'", +filter.Reconciled == null ? "null" : "\'" + filter.Reconciled + "\'");

        }
1
tam tam

Ceci est un exemple d'interrogation de procédure MySQL avec Entity Framework

Voici la définition de ma procédure stockée dans MySQL:

CREATE PROCEDURE GetUpdatedAds (
    IN curChangeTracker BIGINT
    IN PageSize INT
) 
BEGIN
   -- select some recored...
END;

Et voici comment je l'interroge en utilisant Entity Framework:

 var curChangeTracker = new SqlParameter("@curChangeTracker", MySqlDbType.Int64).Value = 0;
 var pageSize = new SqlParameter("@PageSize", (MySqlDbType.Int64)).Value = 100;

 var res = _context.Database.SqlQuery<MyEntityType>($"call GetUpdatedAds({curChangeTracker}, {pageSize})");

Notez que j'utilise C # String Interpolation pour construire ma chaîne de requête.

0
Hooman Bahreini