如何阻止WCF序列化的实体框架类尝试延迟加载



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

我基本上得到了与这里提到的相同的错误ObjectContext实例已被释放-Winforms Entity Framework,不同之处在于我使用的是Silverlight应用程序中的WCF服务。

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

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

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

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

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

值得一提的是,DB中没有外键是很疯狂的。他们应该在那里,就这样。

就你的问题而言。。。听起来您想要返回一个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公开您的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之间的转换,但这只是一个人为的例子。

最新更新