我读过几篇关于实体框架生成的对象的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之间的转换,但这只是一个人为的例子。