sql - 禁用延迟加载和急切加载实体引用未按预期工作

标签 sql wcf entity-framework c#-4.0 wcf-ria-services

我一直在使用 WCF RIA 服务和 Silverlight,并且在公开提供从现有 SQL Server 2008 Express 数据库建模的 ADO.NET 实体数据模型中获取的数据的服务方面取得了一些成功。数据库定义了我希望能够使用客户端进行数据绑定(bind)的表之间的许多关系。

一切进展顺利,直到我尝试执行以下服务方法:

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 个导航属性“用户”和“发送者”。当我遍历“自我”查询的结果时,我看到前面提到的属性已被当前用户填充(这是正确的)。但是,当我从“ friend ”查询中迭代结果时,这两个属性都是空的(在被序列化到客户端之前)。

我试过设置:
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();
});

据我了解,“加载”操作会导致在数据库上执行单独的查询。如您所见,当用户有很多 friend 和很多时间线帖子时,这会出现潜在的低效情况。我试图通过禁用延迟加载来避免的确切情况。我想向客户端返回一个完全加载的实体,该实体可以尽可能少地绑定(bind)到查询。

我已经通过在域服务向导生成的元数据属性定义上应用 [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);

导航属性不再具有任何值(value)。现在这只是一个猜测,但我只能假设它将属性值投影到一个新的对象实例中,所以它不会重新填充这些属性以避免循环引用?无论如何,这是一个需要解决的问题。希望有人比我更了解这件事。

最佳答案

好吧,我设法找到了一些解决方法,尽管不是一个非常优雅的解决方法。我会将它作为答案发布,以便人们可以查看它,但如果可能的话,我将保留这个问题并相信更合适的解决方案。

这是我的修复:

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

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

关于sql - 禁用延迟加载和急切加载实体引用未按预期工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7617253/

相关文章:

sql查询中的python列表作为参数

sql - 如何从 SQL Server 数据库可视化 nvarchar(max) 的值,其中 max>65535?

c# - WCF、NetTcpBinding、Streamed 传输模式可以双工吗?

c# - TPC 继承错误

c# - Entity Framework Linq 查询 : runs instantly in SSMS and 8-10s in EF LINQ 出现问题

sql - 正确的sql结构

sql - 使用GORM在Grails中使用一对多引用有效地检索对象

wcf - 在 WCF-netTCPBinding 中测试 TLS 安全性

.net - 如何以编程方式配置 WCF 已知类型?

c# - 有谁知道 EF6 和 AutoMapper 进行枚举转换时发生了什么