我一直在使用WCF RIA Services和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);
}
注意:'User'是类的内部属性,用于选择当前经过身份验证的用户,Database仅包装ObjectContext属性(为方便起见)。
“时间轴”实体包含2个导航属性“用户”和“发件人”,它们与“Silverfish用户”实体相关联。当我迭代“自我”查询的结果时,我看到前面提到的属性已经被当前用户填充(这是正确的)。但是,当我从'friends'查询迭代结果时,两个属性都为null(在序列化到客户端之前)。
我尝试过设置:
this.ContextOptions.LazyLoadingEnabled = false;
//and
this.ContextOptions.ProxyCreationEnabled = false;
我也尝试使用Include查询方法(启用和禁用延迟加载)来急切加载引用无效。
我成功填写时间轴实体的User和Sender属性的唯一方法是使用以下语句:
friends.ForEach(s => {
if (!s.UserReference.IsLoaded) s.UserReference.Load();
if (!s.SenderReference.IsLoaded) s.SenderReference.Load();
});
根据我的理解,'加载'操作导致在数据库上执行单独的查询。正如您所看到的,当用户拥有许多包含许多时间轴帖子的朋友时,这会带来潜在的低效率。我试图通过禁用延迟加载来避免的确切情况。我想向客户端返回一个完全加载的实体,该实体可以在尽可能少的查询中绑定。
我已经克服了一个问题,即通过在域服务向导生成的元数据属性定义上应用[Include]属性,相对属性未序列化到客户端。这个问题似乎有点复杂,我试过的解决方案已经被其他人广泛宣称,应该在理论上解决我的问题,但事实并非如此。同样,我能够成功填充实体的唯一方法是使用生成的EntityReference&lt;&gt;显式加载引用。为相关属性创建的属性。
非常感谢有关此问题的任何帮助,经验或信息。
[编辑]当我执行这样的查询时,我的一些研究的更新:
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);
导航属性不再具有任何值。现在这只是一个猜测,但我只能假设它将属性值投影到一个新的对象实例中,所以它不会重新填充这些属性以避免循环引用?无论如何,这是一个要解决的泡菜。希望那里的人比我更了解这个。
答案 0 :(得分:0)
我已经设法找到了一些解决方法,虽然不是很优雅。我会将其作为答案发布,以便人们可以查看它,但如果可能的话,我会打开问题并提供更合适的解决方案。
这是我的修复:
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.Include("Friend.Timeline")
where (User.Id == x.UserId)
select x.Friend.Timeline;
List<Timeline> highlights = new List<Timeline>();
highlights.AddRange(self);
friends.ForEach(x => x.ForEach(y => highlights.Add(y)));
return highlights.AsQueryable().OrderByDescending(s => s.Id);
}
我认为这个工作的原因是手动创建新集合,我阻止将实体投影到新对象中,从而保留加载的关系属性。同样,这只是推测,但假设遵循相当好的模式lol。