实体框架中存储过程的返回值映射

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 类的情况下将额外属性检索到联系人中。

【讨论】:

以上是关于实体框架中存储过程的返回值映射的主要内容,如果未能解决你的问题,请参考以下文章

使用实体框架获取存储过程输出参数抛出映射错误:数据读取器与指定的不兼容

JPA - 映射来自实体的附加计算值

实体框架 - 具有多个结果集的存储过程 - 没有行返回

如何从实体框架中的存储过程中获取结果+数据库优先

实体框架 - 您能否将导入的存储过程的结果类型映射到自定义实体类型?

如何通过实体框架将空值传递给存储过程?