【问题标题】:How to stop a WCF serialized Entity Framework class from trying to Lazy Load?如何阻止 WCF 序列化实体框架类尝试延迟加载?
【发布时间】:2013-11-25 02:10:36
【问题描述】:

我已经阅读了几个关于实体框架生成对象的 WCF 序列化的问题/文章,但我发现的所有解决方案都涉及打开预加载,这正是我试图不做的事情。

我基本上遇到了与此处提到的 The ObjectContext instance has been disposed - Winforms Entity Framework 相同的错误,不同之处在于我正在使用 Silverlight 应用程序中的 WCF 服务。

我有一个表 User_Notifications,它有一个表 User_Info 的外键。 (如果我没有正确使用术语,单个User_Info 可以指向多个User_Notifications)。我正在使用 Entity Framework 4,它为这两个创建了一个类。我有一个返回的 WCF 调用:

return DBEntity.User_Notifications.Where(w => w.UserGUID == UserGuid && w.IsDismissed == false).ToArray();

这为我提供了我需要的所有 User_Notifications,但我在客户端收到一个 ObjectContext Instance has been disposed 错误,这看起来像是尝试加载关联的 User_Info 类。我不想要User_Info 数据,我希望它保持为空或其他什么,我不需要它来显示通知。

那么,如何在不需要传递关联对象的情况下传递我的实体对象?

我的老板说这只是“我们在数据库中不需要外键”的另一个原因,我真的不想走这条路。

【问题讨论】:

  • 听起来你的老板应该坚持与编程无关的事情。
  • @Matthew 我的老板是框架开发人员,过去 10 年一直如此。几个月前,我向他展示了一个很酷的新东西,叫做 .net 字典。
  • 可能有用:geekswithblogs.net/danemorgridge/archive/2010/05/04/…(禁用延迟加载)
  • @Matthew 但是默认情况下不会同时加载 User_Notifications 和 User_Info 吗?
  • 不,它只会加载User_Notifications,我要发布答案,所以请抓住你的帽子。

标签: c# wcf entity-framework


【解决方案1】:

对于它的价值,在数据库中没有外键是疯狂的。他们应该在那里,期间。

就您的问题而言...听起来您想返回 User_Notifications 的集合,其中未在初始查询中加载 User_Info 对象,对吗?默认情况下,对表的查询不应急切加载关联的对象。

在您的服务功能中,只需执行以下操作:

return (from n in DBEntity.User_Notifications
        where n.UserGUID == UserGuid && n.IsDismissed == false
        select n).ToArray();

如果你发现你需要客户端的User_Info对象,那么只要把上面的改成:

return (from n in DBEntity.User_Notifications.Include("User_Info")
....

【讨论】:

  • 我认为问题在于导航属性正在被 WCF 中的序列化机制延迟加载。
  • @Matthew 是的,这就是问题所在。我的客户端在尝试加载不存在的关联 User_Info 对象时出错。
  • 您可以配置您的数据库模型以禁用实体模型设计器中的延迟加载(我总是这样做)。如果单击背景,该选项位于属性窗口中。 WCF 不应该延迟加载任何东西。
  • @Ryan 但是默认情况下不会同时加载User_NotificationsUser_Info
  • 带有 .Include("User_Info") 的第二个版本将加载这两个对象。没有 Include() 的第一个选项根本不会急切加载 User_Info 对象。禁用延迟加载不会启用急切加载。据我所知,没有选项可以默认预先加载所有对象属性。否则,您总是会通过任何 DB 调用下载整个数据库,对吧?
【解决方案2】:

我的建议是不要直接通过 WCF 公开您的 EF 实体,而是通过您的服务公开 DTO。

这有两个优点,首先,您正在处理真正的 POCO(不是延迟加载的代理),其中没有持久的特定细节。第二个是您只公开消费者实际需要的内容,这意味着您可以更改底层实现而无需强制客户端重新编译,并且您不必向他们公开整个数据模型。

在您的示例中,您可以:

// I'm not a fan of the Dto suffix, but it makes this example easier
public class UserNotificationDto 
{
    // the properties you want to expose through WCF 
    public Guid UserGuid { get; set; }
    public string Message { get; set; }
    // ...        
}

// your service method
IEnumerable<UserNotificationDto> GetNotifications(Guid userGuid)
{
    using (var ctx = new Context())
    {
        return ctx.User_Notifications
            .Where(x => !x.IsDismissed && x.UserGuid == userGuid)
            .Select(
                x => new UserNotificationDto { 
                    UserGuid = x.UserGuid, 
                    Message = x.Message 
                }
            ).ToList();
    }
}

您可以使用 automapper 来简化 EF 实体和 DTO 之间的转换,但这只是一个人为的示例。

【讨论】:

  • 我同意这是更好的方法,但在这种情况下,归结为我有很多代码要编写,而且截止日期很短(为什么我当我是一名 MF 程序员时,我在周日晚上工作)。实体对象本身在某些情况下会暴露出来,因为它允许客户端进行更改,然后将它们发送回 Web 服务以保存更改。这并不理想,但至少这些网络服务不会被任何东西调用,除了我在这里写的(外部网络服务像你描述的那样工作)
  • 我一直按照您的描述进行操作,但是编写所有内容的时间太长了。从而改变。最后,我们都是最后期限的奴隶。但是,嘿,至少我让框架开发人员最终让我在数据库中添加了一些外键。
  • 也许你最好的选择是装饰你不想序列化的属性。 IgnoreDataMember 属性:msdn.microsoft.com/en-us/library/…
猜你喜欢
  • 1970-01-01
  • 2018-02-22
  • 2012-06-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-20
  • 1970-01-01
相关资源
最近更新 更多