Как вызвать Хранимую процедуру в Entity Framework 6 (Code-First)?

Я очень новичок в 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
}

Моя проблема: как я могу вызвать хранимую процедуру и передать в нее параметры?

Ответ 1

Вы можете вызвать хранимую процедуру в классе DbContext следующим образом.

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

Но если ваша хранимая процедура возвращает несколько наборов результатов в качестве кода примера, вы можете увидеть эту полезную статью в MSDN

Сохраненные процедуры с несколькими наборами результатов

Ответ 2

Все, что вам нужно сделать, это создать объект, который имеет те же имена свойств, что и результаты, возвращаемые хранимой процедурой. Для следующей хранимой процедуры:

    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, используя столько параметров, сколько необходимо.

Ответ 3

Я решил это с 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;
    }
}

это мой ИП:

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

надежда помогла тебе

Ответ 4

Используя ваш пример, вот два способа сделать это:

1 - Использовать отображение хранимых процедур

Обратите внимание, что этот код будет работать с отображением или без него. Если вы отключите отображение объекта, EF сгенерирует оператор вставки + выбора.

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.

Ответ 5

Вы используете MapToStoredProcedures() которая указывает, что вы отображаете свои сущности на хранимые процедуры, при этом вам нужно отпустить тот факт, что есть хранимая процедура, и использовать context как обычно. Как то так (записано в браузере, поэтому не проверено)

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

Если все, что вы действительно пытаетесь сделать, это вызвать хранимую процедуру напрямую, используйте SqlQuery

Ответ 6

Теперь вы можете использовать соглашение, которое я создал, которое позволяет вызывать хранимые процедуры (включая хранимые процедуры, возвращающие несколько наборов результатов), TVF и скалярные UDF изначально из EF.

До тех пор, пока не была выпущена функция Entity Framework 6.1, функции хранилища (т.е. табличные функции и хранимые процедуры) могут использоваться в EF только при выполнении Database First. Были некоторые обходные пути, которые позволили вызвать функции магазина в приложениях Code First, но вы все еще не могли использовать TVF в запросах Linq, что было одним из самых больших ограничений. В EF 6.1 API-интерфейс отображения был опубликован, что (наряду с некоторыми дополнительными настройками) позволило использовать функции хранилища в ваших приложениях Code First.

Подробнее

В течение последних двух недель я сильно затруднялся, и вот это - бета-версия соглашения, которая позволяет использовать функции хранилища (то есть хранимые процедуры, функции, связанные с таблицей и т.д.) в приложениях, которые используют подход Code First и Entity Framework 6.1.1 (или новее). Я более чем доволен исправлениями и новыми функциями, которые включены в этот выпуск.

Подробнее.

Ответ 7

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;  

Ответ 8

Это работает для меня, отбрасывая данные из хранимой процедуры при передаче в параметре.

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

_db - это dbContext

Ответ 9

Взгляните на эту ссылку, которая показывает, как работает сопоставление EF 6 со хранимыми процедурами для вставки, обновления и удаления: http://msdn.microsoft.com/en-us/data/dn468673

Добавление

Вот отличный пример для вызова хранимой процедуры из Code First:

Предположим, что вам нужно выполнить хранимую процедуру с единственным параметром, и эта Хранимая процедура возвращает набор данных, которые соответствуют состояниям Entity, поэтому у нас будет следующее:

var countryIso = "AR"; //Argentina

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

Теперь скажем, что мы хотим выполнить еще одну хранимую процедуру с двумя параметрами:

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

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

Обратите внимание, что мы используем индексирование имен для параметров. Это связано с тем, что Entity Framework будет обертывать эти параметры как объекты DbParameter для вас, чтобы избежать проблем с SQL-инъекциями.

Надеюсь, что этот пример поможет!

Ответ 10

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

Ответ 11

Это работает для меня в коде в первую очередь. Возвращает список с соответствующим свойством модели представления (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();

Обновлено для контекста

Контекст является экземпляром класса, который наследует DbContext, как показано ниже.

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

var Context = new  ApplicationDbContext();

Ответ 12

Бесшумный пассажир имеет проект, который позволяет возвращать несколько наборов результатов из хранимой процедуры, используя инфраструктуру сущности. Один из его примеров ниже....

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

Ответ 13

если вы хотите передать параметры таблицы в хранимую процедуру, вам необходимо установить свойство 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();

Ответ 14

Это то, что 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);
}

Ответ 15

Когда 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.

Ответ 16

Я обнаружил, что вызов хранимых процедур в подходе Code First не удобен. Я предпочитаю использовать 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);

Я считаю, что второй кусок кода проще для понимания.

Ответ 17

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

Ответ 18

Ничего не нужно делать... когда вы создаете 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; }
}

Ответ 19

Использование MySql и Entity Framework Code Первый подход:

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