我对 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
}
我的问题是:如何调用存储过程并将参数传递给它?
您可以在 DbContext
类中调用存储过程,如下所示。
this.Database.SqlQuery<YourEntityType>("storedProcedureName",params);
但是,如果您的存储过程返回多个结果集作为您的示例代码,那么您可以在 MSDN 上看到这篇有用的文章
Stored Procedures with Multiple Result Sets
您所要做的就是创建一个与存储过程返回的结果具有相同属性名称的对象。对于以下存储过程:
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
。
我用 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
希望对你有所帮助。
使用您的示例,这里有两种方法可以完成此操作:
方法 #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
对象。
您正在使用 MapToStoredProcedures()
,这表明您正在将实体映射到存储过程,在执行此操作时,您需要放弃存在存储过程的事实并正常使用 context
。像这样的东西(写入浏览器所以没有测试)
using(MyContext context = new MyContext())
{
Department department = new Department()
{
Name = txtDepartment.text.trim()
};
context.Set<Department>().Add(department);
}
如果您真正想做的只是直接调用存储过程,请使用 SqlQuery
.MapToStoredProcedures(s =>
配置的存储过程。对 Add
的调用应解析为 .Insert(i => i.HasName("insert_department")
您现在还可以使用我创建的约定,它允许从 EF 本地调用存储过程(包括返回多个结果集的存储过程)、TVF 和标量 UDF。
在实体框架 6.1 发布之前,存储函数(即表值函数和存储过程)只能在执行数据库优先时在 EF 中使用。有一些变通方法可以在 Code First 应用程序中调用存储功能,但您仍然无法在 Linq 查询中使用 TVF,这是最大的限制之一。在 EF 6.1 中,映射 API 被公开,这(以及一些额外的调整)使得在您的 Code First 应用程序中使用存储功能成为可能。
在过去的两周里,我非常努力地推动了它——约定的 beta 版本,它允许在使用 Code First 方法和实体框架 6.1.1 的应用程序中使用存储函数(即存储过程、表值函数等)(或更新)。我对此版本中包含的修复和新功能非常满意。
object[] xparams = {
new SqlParameter("@ParameterWithNumvalue", DBNull.Value),
new SqlParameter("@In_Parameter", "Value"),
new SqlParameter("@Out_Parameter", SqlDbType.Int) {Direction = ParameterDirection.Output}};
YourDbContext.Database.ExecuteSqlCommand("exec StoredProcedure_Name @ParameterWithNumvalue, @In_Parameter, @Out_Parameter", xparams);
var ReturnValue = ((SqlParameter)params[2]).Value;
通过在传递参数时从存储过程中拉回数据,这对我有用。
var param = new SqlParameter("@datetime", combinedTime);
var result =
_db.Database.SqlQuery<QAList>("dbo.GetQAListByDateTime @datetime", param).ToList();
_db
是 dbContext
查看此链接,该链接显示 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
);
现在假设我们要执行另一个带有两个参数的存储过程:
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 注入问题。
希望这个例子有帮助!
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();
}
它首先对我有用。它返回一个具有视图模型匹配属性的列表(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();
我发现以代码优先的方式调用存储过程并不方便。
我更喜欢使用 Dapper
。
以下代码是使用实体框架编写的:
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);
我相信第二段代码更容易理解。
您可以将参数传递给 sp_GetById
并在 ToList()
或 FirstOrDefault();
中获取结果
var param = new SqlParameter("@id", 106);
var result = dbContext
.Database
.SqlQuery<Category>("dbo.sp_GetById @id", param)
.FirstOrDefault();
Mindless passenger 有一个项目,该项目允许使用实体框架从存储过程中返回多个结果集。下面是他的一个例子......
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>();
}
.NET Core 5.0 没有 FromSql
,而是有 FromSqlRaw
以下所有内容都为我工作。这里的 Account
类是 C# 中的实体,具有与数据库中完全相同的表名和列名。
应用配置类如下
class AppConfiguration
{
public AppConfiguration()
{
var configBuilder = new ConfigurationBuilder();
var path = Path.Combine(Directory.GetCurrentDirectory(), "appsettings.json");
configBuilder.AddJsonFile(path, false);
var root = configBuilder.Build();
var appSetting = root.GetSection("ConnectionStrings:DefaultConnection");
sqlConnectionString = appSetting.Value;
}
public string sqlConnectionString { get; set; }
}
DbContext 类:
public class DatabaseContext : DbContext
{
public class OptionsBuild
{
public OptionsBuild()
{
setting = new AppConfiguration();
opsBuilder = new DbContextOptionsBuilder<DatabaseContext>();
opsBuilder.UseSqlServer(setting.sqlConnectionString);
dbOptions = opsBuilder.Options;
}
public DbContextOptionsBuilder<DatabaseContext> opsBuilder { get; set; }
public DbContextOptions<DatabaseContext> dbOptions { get; set; }
private AppConfiguration setting { get; set; }
}
public static OptionsBuild ops = new OptionsBuild();
public DatabaseContext(DbContextOptions<DatabaseContext> options) : base(options)
{
//disable initializer
// Database.SetInitializer<DatabaseContext>(null);
}
public DbSet<Account> Account { get; set; }
}
此代码应该在您的数据访问层中:
List<Account> accounts = new List<Account>();
var context = new DatabaseContext(DatabaseContext.ops.dbOptions);
accounts = await context.Account.ToListAsync(); //direct select from a table
var param = new SqlParameter("@FirstName", "Bill");
accounts = await context.Account.FromSqlRaw<Account>("exec Proc_Account_Select",
param).ToListAsync(); //procedure call with parameter
accounts = context.Account.FromSqlRaw("SELECT * FROM dbo.Account").ToList(); //raw query
如果要将表参数传递给存储过程,则必须为表参数设置 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();
这是 EF(DB first)在 DbContext 类中生成的内容:
public ObjectResult<int> Insert_Department(string department)
{
var departmentParameter = new ObjectParameter("department", department);
return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<int>("insert_department", departmentParameter);
}
当 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.
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();
}
无需做任何事情...当您为代码优先方法创建 dbcontext 时,在 fluent 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; }
}
首先使用MySql和Entity框架代码的方法:
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();
在 MYsql 中创建过程。
delimiter //
create procedure SP_Dasboarddata(fromdate date, todate date)
begin
select count(Id) as count,date,status,sum(amount) as amount from
details
where (Emidate between fromdate and todate)
group by date ,status;
END;
//
创建包含存储过程返回结果集值的类
[Table("SP_reslutclass")]
public class SP_reslutclass
{
[Key]
public int emicount { get; set; }
public DateTime Emidate { get; set; }
public int ? Emistatus { get; set; }
public int emiamount { get; set; }
}
在 Dbcontext 中添加类
public class ABCDbContext:DbContext
{
public ABCDbContext(DbContextOptions<ABCDbContext> options)
: base(options)
{
}
public DbSet<SP_reslutclass> SP_reslutclass { get; set; }
}
调用存储库中的实体
var counts = _Dbcontext.SP_reslutclass.FromSql("call SP_Dasboarddata
('2019-12-03','2019-12-31')").ToList();
"storedProcedureName @param1, @param2"
。params
的类型也是System.Data.SqlClient.SqlParameter[]
。this.Database.SqlQuery<YourEntityType>("storedProcedureName @param1", new System.Data.SqlClient.SqlParameter("@param1", YourParam));