c# - stored - ¿Cómo llamar al procedimiento almacenado en Entity Framework 6(código primero)?
mapear stored procedure entity framework (16)
Soy muy nuevo en Entity Framework 6 y quiero implementar procedimientos almacenados en mi proyecto. Tengo un procedimiento almacenado de la siguiente manera:
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
clase:
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
}
Mi problema es: ¿cómo puedo llamar al procedimiento almacenado y pasarle parámetros?
Ahora también puede usar una convención que creé que permite invocar procedimientos almacenados (incluidos los procedimientos almacenados que devuelven múltiples conjuntos de resultados), TVF y UDF escalares de EF.
Hasta que se publicara Entity Framework 6.1, las funciones de almacenamiento (es decir, funciones con valores de tabla y procedimientos almacenados) se podían usar en EF solo cuando se hacía la base de datos primero. Hubo algunas soluciones que permitieron invocar las funciones de la tienda en las aplicaciones de Code First, pero aún no se podían usar los TVF en las consultas de Linq, lo que era una de las mayores limitaciones. En EF 6.1, la API de mapeo se hizo pública, lo que (junto con algunos ajustes adicionales) hizo posible usar las funciones de la tienda en sus aplicaciones de Code First.
Presioné bastante durante las últimas dos semanas y aquí está la versión beta de la convención que permite usar funciones de almacenamiento (es decir, procedimientos almacenados, funciones de tabla de valores, etc.) en aplicaciones que utilizan el enfoque de Code First y Entity Framework 6.1.1 ( o mas nuevo). Estoy más que contento con las correcciones y las nuevas características que se incluyen en esta versión.
Cuando EDMX cree este tiempo si selecciona el procedimiento almacenado en la opción de selección de tabla, simplemente llame a la tienda procesada usando el nombre del procedimiento ...
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.
Descubrí que la llamada al procedimiento de procedimientos almacenados en el Código Primero no es conveniente. Prefiero usar Dapper
lugar de
El siguiente código fue escrito con Entity Framework
:
var clientIdParameter = new SqlParameter("@ClientId", 4);
var result = context.Database
.SqlQuery<ResultForCampaign>("GetResultsForCampaign @ClientId", clientIdParameter)
.ToList();
El siguiente código fue escrito con Dapper
:
return Database.Connection.Query<ResultForCampaign>(
"GetResultsForCampaign ",
new
{
ClientId = 4
},
commandType: CommandType.StoredProcedure);
Creo que la segunda pieza de código es más fácil de entender.
Eche un vistazo a este enlace que muestra cómo funciona la asignación de EF 6 con procedimientos almacenados para realizar una inserción, actualización y eliminación: http://msdn.microsoft.com/en-us/data/dn468673
Adición
Aquí hay un gran ejemplo para llamar a un procedimiento almacenado desde Code First:
Digamos que tiene que ejecutar un procedimiento almacenado con un solo parámetro, y que el procedimiento almacenado devuelve un conjunto de datos que coinciden con los estados de entidad, por lo que tendremos esto:
var countryIso = "AR"; //Argentina
var statesFromArgentina = context.Countries.SqlQuery(
"dbo.GetStatesFromCountry @p0", countryIso
);
Ahora digamos que queremos ejecutar otro procedimiento almacenado con dos parámetros:
var countryIso = "AR"; //Argentina
var stateIso = "RN"; //Río Negro
var citiesFromRioNegro = context.States.SqlQuery(
"dbo.GetCitiesFromState @p0, @p1", countryIso, stateIso
);
Observe que estamos usando nombres basados en índices para los parámetros. Esto se debe a que Entity Framework ajustará estos parámetros como objetos DbParameter para evitar cualquier problema de inyección de SQL.
Espero que este ejemplo ayude!
Está utilizando MapToStoredProcedures()
que indica que está asignando sus entidades a procedimientos almacenados. Al hacer esto, debe dejar de lado el hecho de que hay un procedimiento almacenado y usar el context
manera normal. Algo como esto ( escrito en el navegador por lo que no está probado )
using(MyContext context = new MyContext())
{
Department department = new Department()
{
Name = txtDepartment.text.trim()
};
context.Set<Department>().Add(department);
}
Si lo único que intenta hacer es llamar directamente a un procedimiento almacenado, entonces use SqlQuery
Esto es lo que EF (DB primero) genera en la clase DbContext:
public ObjectResult<int> Insert_Department(string department)
{
var departmentParameter = new ObjectParameter("department", department);
return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<int>("insert_department", departmentParameter);
}
Esto me funciona al retirar datos de un procedimiento almacenado mientras se pasa un parámetro.
var param = new SqlParameter("@datetime", combinedTime);
var result =
_db.Database.SqlQuery<QAList>("dbo.GetQAListByDateTime @datetime", param).ToList();
_db
es el dbContext
Funciona para mí en el código primero. Devuelve una lista con la propiedad coincidente del modelo de vista (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();
Actualizado para el contexto
El contexto es la instancia de la clase que Hereda DbContext como a continuación.
public class ApplicationDbContext : DbContext
{
public DbSet<City> City { get; set; }
}
var Context = new ApplicationDbContext();
Lo resolví con ExecuteSqlCommand
Ponga su propio método como el mío en DbContext como sus propias instancias:
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);
}
para que pueda tener un método en su código subyacente como este:
[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)
{
int resault;
try
{
using (DBContex reposit = new DBContex())
{
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;
}
}
este es mi 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
la esperanza te ayudó
Puede llamar a un procedimiento almacenado en su clase DbContext
la siguiente manera.
this.Database.SqlQuery<YourEntityType>("storedProcedureName",params);
Pero si su procedimiento almacenado devuelve múltiples conjuntos de resultados como su código de muestra, entonces puede ver este artículo útil en MSDN
Procedimientos almacenados con conjuntos de resultados múltiples
Si desea pasar parámetros de tabla al procedimiento almacenado, debe establecer la propiedad TypeName para sus parámetros de tabla.
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();
Todo lo que tiene que hacer es crear un objeto que tenga los mismos nombres de propiedad que los resultados devueltos por el procedimiento almacenado. Para el siguiente procedimiento almacenado:
CREATE PROCEDURE [dbo].[GetResultsForCampaign]
@ClientId int
AS
BEGIN
SET NOCOUNT ON;
SELECT AgeGroup, Gender, Payout
FROM IntegrationResult
WHERE ClientId = @ClientId
END
crear una clase que se parece a:
public class ResultForCampaign
{
public string AgeGroup { get; set; }
public string Gender { get; set; }
public decimal Payout { get; set; }
}
y luego llame al procedimiento haciendo lo siguiente:
using(var context = new DatabaseContext())
{
var clientIdParameter = new SqlParameter("@ClientId", 4);
var result = context.Database
.SqlQuery<ResultForCampaign>("GetResultsForCampaign @ClientId", clientIdParameter)
.ToList();
}
El resultado contendrá una lista de objetos ResultForCampaign
. Puede llamar a SqlQuery
utilizando tantos parámetros como sea necesario.
Usando su ejemplo, aquí hay dos maneras de lograr esto:
1 - Usar mapeo de procedimientos almacenados
Tenga en cuenta que este código funcionará con o sin mapeo. Si desactiva la asignación en la entidad, EF generará una declaración de inserción + selección.
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 - Llamar directamente al procedimiento almacenado.
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;
}
}
Recomiendo usar el primer enfoque, ya que puede trabajar directamente con el objeto de departamento y no tiene que crear un grupo de objetos de Parámetro Sql.
Mindless pasajeros tiene un proyecto que permite que se devuelvan múltiples conjuntos de resultados desde un proceso almacenado utilizando el marco de entidad. Uno de sus ejemplos a continuación ...
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>();
}
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;
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();
}