【发布时间】:2011-10-01 00:10:16
【问题描述】:
我一直在使用 WCF RIA 服务和 Silverlight,并且在公开提供从现有 SQL Server 2008 Express 数据库建模的 ADO.NET 实体数据模型中获取的数据的服务方面取得了一些成功。数据库定义了我希望能够使用客户端进行数据绑定的表之间的许多关系。
一切进展顺利,直到我尝试执行以下服务方法:
public IQueryable<Timeline> GetHighlights() {
var self = from x in Database.Timelines
where User.Id == x.UserId || User.Id == x.SenderId
select x;
var friends = from x in Database.FriendItems
where User.Id == x.UserId
from y in Database.Timelines
where x.FriendId == y.UserId || x.FriendId == y.SenderId
select y;
return self.Concat(friends).OrderByDescending(s => s.Id);
}
注意:“用户”是选择当前经过身份验证的用户的类的内部属性,数据库仅包装 ObjectContext 属性(为方便起见)。
“时间轴”实体包含与“SilverfishUser”实体相关联的 2 个导航属性“用户”和“发送者”。当我遍历“自我”查询的结果时,我看到前面提到的属性已被当前用户填充(这是正确的)。但是,当我从“朋友”查询中迭代结果时,这两个属性都是空的(在被序列化到客户端之前)。
我试过设置:
this.ContextOptions.LazyLoadingEnabled = false;
//and
this.ContextOptions.ProxyCreationEnabled = false;
我还尝试使用 Include 查询方法(启用和禁用延迟加载)急切加载引用,但无济于事。
我成功填充 Timeline 实体的 User 和 Sender 属性的唯一方法是使用以下语句:
friends.ForEach(s => {
if (!s.UserReference.IsLoaded) s.UserReference.Load();
if (!s.SenderReference.IsLoaded) s.SenderReference.Load();
});
据我了解,“加载”操作会导致在数据库上执行单独的查询。正如你所看到的,当用户有很多朋友和很多时间线帖子时,这会呈现出一种潜在的低效情况。我试图通过禁用延迟加载来避免的确切情况。我想向客户端返回一个完全加载的实体,该实体可以在尽可能少的查询中绑定。
我已经通过在域服务向导生成的元数据属性定义上应用 [Include] 属性来克服一个问题,即相关属性没有序列化到客户端。这个问题似乎有点复杂,我尝试过的解决方案已被其他人广泛陈述,理论上应该可以解决我的问题,但他们没有。同样,我能够成功填充实体的唯一方法是使用为关联属性创建的生成的 EntityReference 属性显式加载引用。
我们将不胜感激有关此问题的任何帮助、经验或信息。
[编辑] 当我执行这样的查询时,我的一些研究的更新:
var friends = Database.FriendItems
.Include("Friend.Timeline")
.Where(s => User.Id == s.UserId);
并且访问导航属性(“friends.First().Friend.Timeline.First().User”)的值不为空。只有当我通过添加以下内容将时间线选择到新集合中时:
.SelectMany(s => s.Friend.Timeline);
导航属性不再具有任何价值。现在这只是一个猜测,但我只能假设它将属性值投影到一个新的对象实例中,所以它不会重新填充这些属性以避免循环引用?无论如何,这是一个需要解决的问题。希望有人比我更了解这一点。
【问题讨论】:
标签: sql wcf entity-framework c#-4.0 wcf-ria-services