实体框架中存储过程的返回值映射
Posted
技术标签:
【中文标题】实体框架中存储过程的返回值映射【英文标题】:Return value mapping on Stored Procedures in Entity Framework 【发布时间】:2010-12-23 17:16:32 【问题描述】:我正在使用 EntityFramework 调用存储过程。但是我在部分实体类中设置的自定义属性为空。 我的 edmx 中有实体(我打电话给 edmx,我不知道该怎么称呼它)。例如,我的数据库中有一个“用户”表,所以我的实体上有一个“用户”类。 我有一个名为 GetUserById(@userId) 的存储过程,在这个存储过程中,我正在编写如下所示的基本 sql 语句
"SELECT * FROM Users WHERE Id=@userId"
在我的 edmx 中,我进行了函数导入以调用此存储过程并将其返回值设置为实体(也从下拉列表中选择用户)。当我像下面这样调用我的存储过程时,它可以完美运行
User user = Context.SP_GetUserById(123456);
但是我在存储过程中添加了一个自定义的新列,以返回一个如下所示的列
SELECT *, dbo.ConcatRoles(U.Id) AS RolesAsString
FROM membership.[User] U
WHERE Id = @id
现在,当我从 SSMS 执行它时,名为 RolesAsString 的新列出现在结果中。 为了在实体框架上工作,我向我的 User 类添加了一个名为 RolesAsString 的新属性,如下所示。
public partial class User
public string RolesAsString get; set;
但是当我调用它时,这个字段并没有被存储过程填充。 我查看我的 SP_GetUserById 的映射详细信息窗口,此窗口上没有映射。我想添加,但窗口是只读的,我无法映射它。我查看了 edmx 的来源,找不到任何关于 SP 映射的信息。
如何映射这个自定义字段?
【问题讨论】:
首先——不要调用你的存储过程sp_(something)
——这个命名是为微软保留的。其次 - 不要在你的存储过程中使用SELECT * FROM...
...
感谢您的评论,为什么您说不要调用“select *”意味着写下所有列名,例如“select Id,Name,Email,....”?
是的 - 当字段添加到数据库时,它可以保护您免受额外字段的影响,这可能会破坏您的 DAL,因为它不期望这些字段。切勿在任何地方使用SELECT *
。现在,进入问题 - 您是否更新了模型浏览器中的函数导入?
是的,我在模型浏览器上更新它,但没有任何反应。我还读到实体框架不查看部分类,因此它不会将“RolesAsString”列映射到实体属性。
有人知道这个吗?我遇到了完全相同的情况,想知道是否有其他方法可以做到这一点。
【参考方案1】:
您必须为 SP 创建一个复杂类型,而不是使用部分类。
【讨论】:
【参考方案2】:尝试将属性添加到模型浏览器中的用户实体。如果在模型中定义它可能会起作用,而不是作为部分类......或者,最后,最简单的可能是让它返回一个实体,并将 SP 结果转换为用户结果,作为最后的手段。
HTH。
【讨论】:
【参考方案3】:非常老的线程,但我今天遇到了这个确切的问题。
一个区别是我没有将 SP 导入 dbContext 而是选择使用 SQLQuery 返回联系人实体列表。
var allContacts = _dbContext.Database.SqlQuery<Contacts>
("CRM.GetAllContactsForCustomer @customerID, param1).ToList();
与 TS 一样,我创建了一个部分类来保存 SP 将返回的额外属性。
public partial class Contacts
public EnumContactOrigin ContactOrigin get; set;
执行 SP 时不会填充此属性,与在 dbContext 中使用导入的 SP 时一样。
出于某种原因,我想出了为联系人创建一个包装类来保存该额外属性的想法。
public class ExtendedContacts : Contacts
public new EnumContactOrigin ContactOrigin get; set;
你猜怎么着,它有效! ContactOrigin 现在可以正确填写。
var allContacts = _dbContext.Database.SqlQuery<ExtendedContacts>
("CRM.GetAllContactsForCustomer @customerID, param1).ToList();
在我的情况下,我可以将它作为一个包装类,因为我只使用联系人列表在网格中显示。
我很想知道为什么这行得通?如果有另一种方法可以在不需要此 ExtendedContacts 类的情况下将额外属性检索到联系人中。
【讨论】:
以上是关于实体框架中存储过程的返回值映射的主要内容,如果未能解决你的问题,请参考以下文章
使用实体框架获取存储过程输出参数抛出映射错误:数据读取器与指定的不兼容