在实体框架中使用存储过程
Posted
技术标签:
【中文标题】在实体框架中使用存储过程【英文标题】:using stored procedure in entity framework 【发布时间】:2014-01-25 01:32:09 【问题描述】:我正在使用带有实体框架的 asp.net mvc 5 和 C#...我有函数的模型和域类...现在我需要使用存储过程...。我正在努力解决这个问题。
我首先关注现有数据库的代码,并且我已经在那里编写了存储过程。我的问题是如何在我的 Web 应用程序中调用该存储过程。
存储过程:
ALTER PROCEDURE [dbo].[GetFunctionByID](
@FunctionId INT
)
AS
BEGIN
SELECT *
FROM Functions As Fun
WHERE Function_ID = @FunctionId
END
领域类:
public class Functions
public Functions()
public int Function_ID get; set;
public string Title get; set;
public int Hierarchy_level get; set;
功能模型:
[Table("Functions")]
public class App_Functions
public App_Functions()
[Key]
public int Function_ID get; set;
[StringLength(50)]
[Required]
public string Title get; set;
public int Hierarchy_level get; set;
//public virtual ICollection<App_Controllers> App_Controllers get; set; */
基本上下文:
public class BaseContext<TContext> : DbContext where TContext : DbContext
static BaseContext()
Database.SetInitializer<TContext>(null);
protected BaseContext()
: base("name = ApplicationDbConnection")
函数上下文:
public class FunctionsContext : BaseContext<FunctionsContext>
public DbSet<App_Functions> Functions get; set;
【问题讨论】:
【参考方案1】:您需要创建一个包含所有存储过程属性的模型类,如下所示。 另外由于Entity Framework模型类需要主键,所以可以使用Guid创建一个假键。
public class GetFunctionByID
[Key]
public Guid? GetFunctionByID get; set;
// All the other properties.
然后在您的DbContext
中注册GetFunctionByID
模型类。
public class FunctionsContext : BaseContext<FunctionsContext>
public DbSet<App_Functions> Functions get; set;
public DbSet<GetFunctionByID> GetFunctionByIds get;set;
当你调用你的存储过程时,请看下面:
var functionId = yourIdParameter;
var result = db.Database.SqlQuery<GetFunctionByID>("GetFunctionByID @FunctionId", new SqlParameter("@FunctionId", functionId)).ToList());
【讨论】:
由于某种原因,我在调试时得到空值反对结果! 这对我不起作用。假密钥不能与实体类命名相同,因为它会导致错误“成员名称不能与其封闭类型相同”。如果我遗漏了密钥,我会在执行时收到模型验证错误,因为它没有密钥。如果我将假密钥命名为其他名称,它会尝试创建一个表。 如何在我的实体类中设置架构? ,我的SP不在dbo上。我收到错误消息:找不到存储过程 'xxx' @Lin 我收到错误消息,存储过程返回的result set
中不存在假密钥【参考方案2】:
导入存储过程后,可以创建存储过程的对象,传递函数的参数
using (var entity = new FunctionsContext())
var DBdata = entity.GetFunctionByID(5).ToList<Functions>();
或者你也可以使用SqlQuery
using (var entity = new FunctionsContext())
var Parameter = new SqlParameter
ParameterName = "FunctionId",
Value = 5
;
var DBdata = entity.Database.SqlQuery<Course>("exec GetFunctionByID @FunctionId ", Parameter).ToList<Functions>();
【讨论】:
【参考方案3】:您可以使用SqlQuery
调用存储过程(参见here)
// Prepare the query
var query = context.Functions.SqlQuery(
"EXEC [dbo].[GetFunctionByID] @p1",
new SqlParameter("p1", 200));
// add NoTracking() if required
// Fetch the results
var result = query.ToList();
【讨论】:
这是否意味着我不需要在 dbcontext 中为每个存储过程和 dbset 创建模型?? @toxic 你把200
改成数据库中某个值的id了吗?
@toxic 您将需要一个 sp 用于每个表的每个 CRUD 操作。 EF6 大大改进了对实体和存储过程之间映射的支持see here
我知道并使用了 id 2,我在数据库表中有记录!
使用 EF6 你可以使用 context.Database.SqlQuery// 将一些租户添加到上下文中,以便我们为过程返回一些内容! 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);
【讨论】:
// ACT // 通过上下文扩展方法调用存储过程获取结果 var results = Context.ExecuteStoredProcedure(procedure); // ASSERT Assert.AreEqual(expectedCount, results.Count++); 如果您想更改某些内容,请不要添加评论;而是点击“编辑”,然后直接应用更改。【参考方案5】: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>();
...我正在研究一个stored procedure framework (here),您可以像下面显示的我的测试方法之一那样调用它...
[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)
如果这两种方法中的任何一种都好?
【讨论】:
【参考方案6】:简单。只需实例化您的实体,将其设置为一个对象并将其传递给您的控制器中的视图。
实体
VehicleInfoEntities db = new VehicleInfoEntities();
存储过程
dbo.prcGetMakes()
或
您可以在存储过程中的方括号 () 内添加任何参数
dbo.prcGetMakes("BMW")
控制器
public class HomeController : Controller
VehicleInfoEntities db = new VehicleInfoEntities();
public ActionResult Index()
var makes = db.prcGetMakes(null);
return View(makes);
【讨论】:
以上是关于在实体框架中使用存储过程的主要内容,如果未能解决你的问题,请参考以下文章