禁用了延迟加载和延迟加载实体引用,它们不能按预期工作



我一直在使用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);
}

注意:'User'是类的内部属性,用于选择当前认证的用户,而Database只是包装了ObjectContext属性(为了方便)。

'Timeline'实体包含两个导航属性'User'和'Sender',它们与'SilverfishUser'实体相关联。当我迭代"self"查询的结果时,我看到前面提到的属性已经被当前用户填充(这是正确的)。然而,当我迭代'friends'查询的结果时,两个属性都是空的(在序列化到客户端之前)。

我试过设置:

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();
});

据我所知,'Load'操作导致在数据库上执行单独的查询。正如您所看到的,当用户有许多朋友和许多时间轴帖子时,这可能会导致效率低下的情况。这正是我试图通过禁用惰性加载来避免的情况。我想返回给客户端一个完全加载的实体,可以在尽可能少的查询中绑定。

通过在Domain Service Wizard生成的元数据属性定义上应用[Include]属性,我已经克服了一个相对属性没有序列化到客户端的问题。这个问题似乎有点复杂,我尝试过的解决方案已经被其他人广泛陈述,理论上应该能解决我的问题,但他们没有。同样,我能够成功填充实体的唯一方法是使用为关联属性创建的生成的EntityReference<>属性显式加载引用。

任何关于这个问题的帮助、经验或信息都将不胜感激。

[EDIT]当我执行这样的查询时,对我的一些研究进行了更新:

    var friends = Database.FriendItems
                .Include("Friend.Timeline")
                .Where(s => User.Id == s.UserId);

并访问导航属性("friends.First(). friend . timeline . first (). user "),该值不为空。只有当我在新集合中选择时间轴时,才会添加如下内容:

.SelectMany(s => s.Friend.Timeline);

导航属性不再有任何值。现在这只是一个猜测,但我只能假设它将属性值投影到一个新的对象实例中,所以它不会重新填充这些属性,以避免循环引用?不管怎样,这是一个棘手的问题。希望有人比我更了解这个

好吧,我已经设法找到了一个变通办法,虽然不是很优雅的一个。我将把它作为一个答案贴出来,这样人们就可以看看了,但我将把这个问题留下,如果可能的话,我将给出一个更合适的解决方案。

这是我的解决方案:

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);
}

I 认为这样做的原因是通过手动创建新集合,我防止实体被投影到新对象中,从而保留了加载的关系属性。再一次,这只是猜测,但假设遵循了一个很好的模式,哈哈。

最新更新