web-dev-qa-db-ja.com

Entity Framework 6でストレージプロジャを呼び出す方法(コード優先)

私はEntity Framework 6を​​初めて使うので、自分のプロジェクトにストアドプロシージャを実装したいと思います。次のようなストアドプロシージャがあります。

ALTER PROCEDURE [dbo].[insert_department]
    @Name [varchar](100)
AS
BEGIN
    INSERT [dbo].[Departments]([Name])
    VALUES (@Name)

    DECLARE @DeptId int

    SELECT @DeptId = [DeptId]
    FROM [dbo].[Departments]
    WHERE @@ROWCOUNT > 0 AND [DeptId] = SCOPE_IDENTITY()

    SELECT t0.[DeptId]
    FROM [dbo].[Departments] AS t0
    WHERE @@ROWCOUNT > 0 AND t0.[DeptId] = @DeptId
END

Departmentクラス:

public class Department
{
    public int DepartmentId { get; set; }       
    public string Name { get; set; }
}

modelBuilder 
.Entity<Department>() 
.MapToStoredProcedures(s => 
s.Update(u => u.HasName("modify_department") 
               .Parameter(b => b.Department, "department_id") 
               .Parameter(b => b.Name, "department_name")) 
 .Delete(d => d.HasName("delete_department") 
               .Parameter(b => b.DepartmentId, "department_id")) 
 .Insert(i => i.HasName("insert_department") 
               .Parameter(b => b.Name, "department_name")));

protected void btnSave_Click(object sender, EventArgs e)
{
    string department = txtDepartment.text.trim();

    // here I want to call the stored procedure to insert values
}

私の問題は次のとおりです。 /ストアドプロシージャを呼び出してパラメータを渡す方法を教えてください。

239
Jaan

以下のようにDbContextクラスのストアドプロシージャを呼び出すことができます。

this.Database.SqlQuery<YourEntityType>("storedProcedureName",params);

ただし、ストアドプロシージャがサンプルコードとして複数の結果セットを返す場合は、MSDNでこの役に立つ記事を見ることができます。

複数の結果セットを持つストアドプロシージャ

230
Alborz

ストアドプロシージャから返される結果と同じプロパティ名を持つオブジェクトを作成するだけです。次のストアドプロシージャの場合

    CREATE PROCEDURE [dbo].[GetResultsForCampaign]  
    @ClientId int   
    AS
    BEGIN
    SET NOCOUNT ON;

    SELECT AgeGroup, Gender, Payout
    FROM IntegrationResult
    WHERE ClientId = @ClientId
    END

次のようなクラスを作成してください。

    public class ResultForCampaign
    {
        public string AgeGroup { get; set; }

        public string Gender { get; set; }

        public decimal Payout { get; set; }
    }

そして、次のようにしてプロシージャを呼び出します。

    using(var context = new DatabaseContext())
    {
            var clientIdParameter = new SqlParameter("@ClientId", 4);

            var result = context.Database
                .SqlQuery<ResultForCampaign>("GetResultsForCampaign @ClientId", clientIdParameter)
                .ToList();
    }

結果はResultForCampaignオブジェクトのリストを含みます。 SqlQueryは必要に応じていくつでもパラメータを使って呼び出すことができます。

140
Filipe Leite

ExecuteSqlCommandで解決しました

私のようなあなた自身のメソッドをあなた自身のインスタンスとしてDbContextに入れてください:

public void addmessage(<yourEntity> _msg)
{
    var date = new SqlParameter("@date", _msg.MDate);
    var subject = new SqlParameter("@subject", _msg.MSubject);
    var body = new SqlParameter("@body", _msg.MBody);
    var fid = new SqlParameter("@fid", _msg.FID);
    this.Database.ExecuteSqlCommand("exec messageinsert @Date , @Subject , @Body , @Fid", date,subject,body,fid);
}

だからあなたはこのようなあなたのコードビハインドでメソッドを持つことができます:

[WebMethod] //this method is static and i use web method because i call this method from client side
public static void AddMessage(string Date, string Subject, string Body, string Follower, string Department)
{
    try
    {
        using (DBContext reposit = new DBContext())
        {
            msge <yourEntity> Newmsg = new msge();
            Newmsg.MDate = Date;
            Newmsg.MSubject = Subject.Trim();
            Newmsg.MBody = Body.Trim();
            Newmsg.FID= 5;
            reposit.addmessage(Newmsg);
        }
    }
    catch (Exception)
    {
        throw;
    }
}

これは私のSPです。

Create PROCEDURE dbo.MessageInsert

    @Date nchar["size"],
    @Subject nchar["size"],
    @Body nchar["size"],
    @Fid int
AS
    insert into Msg (MDate,MSubject,MBody,FID) values (@Date,@Subject,@Body,@Fid)
    RETURN

あなたを助けてくれることを願っています

45

あなたの例を使用して、これを達成するための2つの方法があります。

1 - ストアドプロシージャマッピングを使用する

このコードは、マッピングの有無にかかわらず機能します。エンティティのマッピングを無効にすると、EFはinsert + select文を生成します。

protected void btnSave_Click(object sender, EventArgs e)
{
     using (var db = DepartmentContext() )
     {
        var department = new Department();

        department.Name = txtDepartment.text.trim();

        db.Departments.add(department);
        db.SaveChanges();

        // EF will populate department.DepartmentId
        int departmentID = department.DepartmentId;
     }
}

2 - ストアドプロシージャを直接呼び出す

protected void btnSave_Click(object sender, EventArgs e)
{
     using (var db = DepartmentContext() )
     {
        var name = new SqlParameter("@name, txtDepartment.text.trim());

        //to get this to work, you will need to change your select inside dbo.insert_department to include name in the resultset
        var department = db.Database.SqlQuery<Department>("dbo.insert_department @name", name).SingleOrDefault();

       //alternately, you can invoke SqlQuery on the DbSet itself:
       //var department = db.Departments.SqlQuery("dbo.insert_department @name", name).SingleOrDefault();

        int departmentID = department.DepartmentId;
     }
}

部署オブジェクトを直接操作してSqlParameterオブジェクトの束を作成する必要がないため、最初の方法を使用することをお勧めします。

16

エンティティをストアドプロシージャにマッピングしていることを示すMapToStoredProcedures()を使用しています。これを行うときは、ストアドプロシージャがあることを放棄し、通常どおりにcontextを使用する必要があります。このようなもの( ブラウザに書かれているのでテストされていない

using(MyContext context = new MyContext())
{
    Department department = new Department()
    {
        Name = txtDepartment.text.trim()
    };
    context.Set<Department>().Add(department);
}

あなたが本当にしようとしているのが直接ストアドプロシージャを呼び出すことであるならば、それから SqlQuery を使ってください

15
qujck

また、ストアード・プロシージャー(複数の結果セットを返すストアード・プロシージャーを含む)、TVF、およびスカラーUDFをEFからネイティブに呼び出すことを可能にする、私が作成した規則を使用することもできます。

Entity Framework 6.1がリリースされるまでは、ストア関数(つまりテーブル値関数とストアドプロシージャ)は、データベース優先を実行する場合にのみEFで使用できました。 Code Firstアプリでストア関数を呼び出すことを可能にするいくつかの回避策がありましたが、それでも最大の制限の1つであるLinqクエリでTVFを使用できませんでした。 EF 6.1では、マッピングAPIが公開され、(追加の調整と共に)Code Firstアプリでストア関数を使用できるようになりました。

続きを読む

私は過去2週間非常に懸命に取り組んできましたが、それがここにあります - コードファーストアプローチとEntity Framework 6.1.1を使用するアプリケーションでストア関数(ストアドプロシージャ、テーブル値関数など)を使用できるようにする規約のベータ版または新しい)。このリリースに含まれる修正と新機能に満足しています。

続きを読む

12
Pawel

これは、パラメータを渡している間にストアドプロシージャからデータを引き戻すことによって私には有効です。

var param = new SqlParameter("@datetime", combinedTime);
var result = 
        _db.Database.SqlQuery<QAList>("dbo.GetQAListByDateTime @datetime", param).ToList();

_dbはdbContextです

10
Tom Stickel

挿入、更新、および削除を行うためのストアドプロシージャとEF 6のマッピングの仕組みを示すこのリンクを見てください。 http://msdn.Microsoft.com/en-us/data/dn468673

加算

これは、Code Firstからストアドプロシージャを呼び出す優れた例です。

単一のパラメータを使用してストアドプロシージャを実行する必要があり、そのストアドプロシージャはエンティティの状態と一致するデータのセットを返すとします。

var countryIso = "AR"; //Argentina

var statesFromArgentina = context.Countries.SqlQuery(
                                      "dbo.GetStatesFromCountry @p0", countryIso
                                                    );

2つのパラメータを使って別のストアドプロシージャを実行したいとしましょう。

var countryIso = "AR"; //Argentina
var stateIso = "RN"; //Río Negro

var citiesFromRioNegro = context.States.SqlQuery(
                            "dbo.GetCitiesFromState @p0, @p1", countryIso, stateIso
                          );

パラメータにインデックスベースの命名を使用していることに注意してください。これは、SQLインジェクションの問題を回避するために、Entity FrameworkがこれらのパラメーターをDbParameterオブジェクトとしてラップするためです。

この例が役立つことを願っています!

object[] xparams = {
            new SqlParameter("@ParametterWithNummvalue", DBNull.Value),
            new SqlParameter("@In_Parameter", "Value"),
            new SqlParameter("@Out_Parameter", SqlDbType.Int) {Direction = ParameterDirection.Output}};

        YourDbContext.Database.ExecuteSqlCommand("exec StoreProcedure_Name @ParametterWithNummvalue, @In_Parameter, @Out_Parameter", xparams);
        var ReturnValue = ((SqlParameter)params[2]).Value;  
9
Shiraj Momin
public IList<Models.StandardRecipeDetail> GetRequisitionDetailBySearchCriteria(Guid subGroupItemId, Guid groupItemId)
{
    var query = this.UnitOfWork.Context.Database.SqlQuery<Models.StandardRecipeDetail>("SP_GetRequisitionDetailBySearchCriteria @SubGroupItemId,@GroupItemId",
    new System.Data.SqlClient.SqlParameter("@SubGroupItemId", subGroupItemId),
    new System.Data.SqlClient.SqlParameter("@GroupItemId", groupItemId));
    return query.ToList();
}
6

最初はコードで動作します。ビューモデル(StudentChapterCompletionViewModel)のプロパティが一致するリストを返します

var studentIdParameter = new SqlParameter
{
     ParameterName = "studentId",
     Direction = ParameterDirection.Input,
     SqlDbType = SqlDbType.BigInt,
     Value = studentId
 };

 var results = Context.Database.SqlQuery<StudentChapterCompletionViewModel>(
                "exec dbo.sp_StudentComplettion @studentId",
                 studentIdParameter
                ).ToList();

コンテキスト用に更新

Contextは、DbContextを継承したクラスのインスタンスです。

public class ApplicationDbContext : DbContext
{
    public DbSet<City> City { get; set; }
}

var Context = new  ApplicationDbContext();
4
reza.cse08

マインドレスパッセンジャー エンティティフレームワークを使用してストアドプロシージャから複数の結果セットを返すことができるプロジェクトがあります。下記の彼の例の1つ....

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>();
}
1
Dib

テーブルパラメータをストアドプロシージャに渡したい場合は、テーブルパラメータにTypeNameプロパティを設定する必要があります。

SqlParameter codesParam = new SqlParameter(CODES_PARAM, SqlDbType.Structured);
            SqlParameter factoriesParam = new SqlParameter(FACTORIES_PARAM, SqlDbType.Structured);

            codesParam.Value = tbCodes;
            codesParam.TypeName = "[dbo].[MES_CodesType]";
            factoriesParam.Value = tbfactories;
            factoriesParam.TypeName = "[dbo].[MES_FactoriesType]";


            var list = _context.Database.SqlQuery<MESGoodsRemain>($"{SP_NAME} {CODES_PARAM}, {FACTORIES_PARAM}"
                , new SqlParameter[] {
                   codesParam,
                   factoriesParam
                }
                ).ToList();
0
trueboroda

コードファーストアプローチでストアドプロシージャを呼び出すのは便利ではないことがわかりました。代わりにDapperを使うのが好きです。

次のコードはEntity Frameworkで書かれています。

var clientIdParameter = new SqlParameter("@ClientId", 4);

var result = context.Database
.SqlQuery<ResultForCampaign>("GetResultsForCampaign @ClientId", clientIdParameter)
.ToList();

次のコードはDapperで書かれています。

return Database.Connection.Query<ResultForCampaign>(
            "GetResultsForCampaign ",
            new
            {
                ClientId = 4
            },
            commandType: CommandType.StoredProcedure);

2番目のコードは理解しやすいと思います。

0

なにもする必要はありません。コードの最初のアプローチとしてdbcontextを作成する場合は、流れるようなAPI領域の下の名前空間を初期化し、spのリストを作成し、それを必要な場所に使用します。

public partial class JobScheduleSmsEntities : DbContext
{
    public JobScheduleSmsEntities()
        : base("name=JobScheduleSmsEntities")
    {
        Database.SetInitializer<JobScheduleSmsEntities>(new CreateDatabaseIfNotExists<JobScheduleSmsEntities>());
    }

    public virtual DbSet<Customer> Customers { get; set; }
    public virtual DbSet<ReachargeDetail> ReachargeDetails { get; set; }
    public virtual DbSet<RoleMaster> RoleMasters { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        //modelBuilder.Types().Configure(t => t.MapToStoredProcedures());

        //modelBuilder.Entity<RoleMaster>()
        //     .HasMany(e => e.Customers)
        //     .WithRequired(e => e.RoleMaster)
        //     .HasForeignKey(e => e.RoleID)
        //     .WillCascadeOnDelete(false);
    }
    public virtual List<Sp_CustomerDetails02> Sp_CustomerDetails()
    {
        //return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<Sp_CustomerDetails02>("Sp_CustomerDetails");
        //  this.Database.SqlQuery<Sp_CustomerDetails02>("Sp_CustomerDetails");
        using (JobScheduleSmsEntities db = new JobScheduleSmsEntities())
        {
           return db.Database.SqlQuery<Sp_CustomerDetails02>("Sp_CustomerDetails").ToList();

        }

    }

}

}

public partial class Sp_CustomerDetails02
{
    public long? ID { get; set; }
    public string Name { get; set; }
    public string CustomerID { get; set; }
    public long? CustID { get; set; }
    public long? Customer_ID { get; set; }
    public decimal? Amount { get; set; }
    public DateTime? StartDate { get; set; }
    public DateTime? EndDate { get; set; }
    public int? CountDay { get; set; }
    public int? EndDateCountDay { get; set; }
    public DateTime? RenewDate { get; set; }
    public bool? IsSMS { get; set; }
    public bool? IsActive { get; set; }
    public string Contact { get; set; }
}
0
SHUBHASIS

MySqlとEntity Frameworkのコードを最初に使用する

public class Vw_EMIcount
{
    public int EmiCount { get; set; }
    public string Satus { get; set; }
}

var result = context.Database.SqlQuery<Vw_EMIcount>("call EMIStatus('2018-3-01' ,'2019-05-30')").ToList();
0
Hari Lakkakula
public static string ToSqlParamsString(this IDictionary<string, string> dict)
        {
            string result = string.Empty;
            foreach (var kvp in dict)
            {
                result += $"@{kvp.Key}='{kvp.Value}',";
            }
            return result.Trim(',', ' ');
        }

public static List<T> RunSproc<T>(string sprocName, IDictionary<string, string> parameters)
        {
            string command = $"exec {sprocName} {parameters.ToSqlParamsString()}";
            return Context.Database.SqlQuery<T>(command).ToList();
        }
0
user1883961

これはEF(DBファースト)がDbContextクラスで生成するものです。

public ObjectResult<int> Insert_Department(string department)
{
    var departmentParameter = new ObjectParameter("department", department);

    return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<int>("insert_department", departmentParameter);
}
0
IngoB

あなたがテーブル選択オプションでストアドプロシージャを選択した場合、EDMXが今回作成するときは、単にプロシージャ名を使用してストアドプロシージャを呼び出す...

var num1 = 1; 
var num2 = 2; 

var result = context.proc_name(num1,num2).tolist();// list or single you get here.. using same thing you can call insert,update or delete procedured.
0
Shafiq Rabbi