我一直在使用WCF RIA Services和Silverlight,并且已经在公开提供服务的服务中取得了一些成功,该服务为从ADO.NET实体数据模型从现有的SQL Server 2008 Express数据库。数据库定义了我希望能够使用客户端进行数据绑定的表之间的许多关系。禁用延迟加载和急切加载实体引用不按预期方式工作
一切都进展顺利直到我试图执行下列服务方法:
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属性的类的内部属性(为了方便)。
'时间轴'实体包含2个与'SilverfishUser'实体关联的导航属性'User'和'Sender'。当我迭代'self'查询的结果时,我发现前面提到的属性已经被当前用户填充(这是正确的)。但是,当我迭代“朋友”查询的结果时,这两个属性都为空(在序列化到客户端之前)。
我已经尝试设置:
this.ContextOptions.LazyLoadingEnabled = false;
//and
this.ContextOptions.ProxyCreationEnabled = false;
而且我自己也尝试渴望加载使用包括查询方式引用(和延迟加载的启用和已禁用)无济于事。
我已经成功地填补了时间轴实体的用户和发件人性能的唯一方法是使用下面的语句:
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“)的值不为null。只有当我通过添加如下内容来选择时间轴到新集合中时:
.SelectMany(s => s.Friend.Timeline);
导航属性不再有任何值。现在这只是一个猜测,但我只能假定它将属性值投影到一个新的对象实例中,所以它不会重新填充这些属性以避免循环引用?无论如何,这是一个解决问题的窍门。希望有一些人比我更了解这方面的知识。