【问题标题】:LINQ To Entities Include + Where MethodLINQ To Entities Include + Where 方法
【发布时间】:2013-10-23 13:39:23
【问题描述】:

我有 NxN 表,想象一下:

User(id, ...) Addresses(id, ...)

UserAddresses 包含用户和地址的 FK。 据我所知,Entity Framework User 创建的 Entity 包含一个 UserAddresses 的集合。 Address 包含一个 UserAddresses 的集合,而一个特定的 UserAddress 包含一个对 User 和一个 Address 的引用。

现在我想通过 linq 进行下一个查询。 对于特定的用户 ID,仅获取启用标志设置为 true 的 userAddresses。 对于特定的用户 id,userAddresses 可以包含多个条目,但只为该特定用户设置一个。

我能做的查询是:

context.User.Include( x => x.UserAddresses )
            .Include( x => x.UserAddresses.Select(y => y.Address) )
            .Single( x => x.id == USER_ID )

但我真正想要的不是为该用户加载所有 UserAddresses...只有包含启用的那个,设置为 TRUE!

有人可以帮我做这个查询吗?

【问题讨论】:

  • 您使用的是哪种Include?据我所知System.Data.Objects.ObjectQueryInclude 方法只接收1 个字符串参数?
  • @KingKing 我做了一个扩展方法,将 lambda 表达式格式化为字符串并将其传递给“本机”ObjectQuery 包含方法。
  • 如果是这样,你的问题的答案是impossibleInclude没有那么强大,你不能在包含之前执行任何filter

标签: c# .net linq entity-framework include


【解决方案1】:

在 EF 中无法部分加载关联属性。尝试选择匿名类型以仅获取您需要的内容:

var result = context.User
   .Where(u => u.Id == userId)
   .Select(u => new {
       Addresses = u.UserAddresses.Select(ua => ua.Address)
            .Where(a => a.Enabled),
       User = u // if you need this as well 
   })
   .Single();

这不会加载 result.User.UserAddresses,但 result.Addresses 将包含您想要的内容。

如果您真的想将所有内容作为 User 类的一部分返回,则需要分离 result.User,然后更新 result.User.UserAddresses 以指向 result.Addresses。

【讨论】:

  • 我需要返回所有相关的用户实体,但不是所有的集合映射。所以我认为匿名类型不正确:/
  • @goncaloRD:不幸的是,where 条件无法使用Include 的条件。这是您的最佳选择。
  • @ChaseMedallion 谢谢,这正是我所需要的。查询完美完成,EF 对象按照我想要的方式映射。我创建了一个类型来对我的对象进行类型化,以便在我的业务层中使用。
【解决方案2】:

另一种选择是使用Load() 而不是Include()

var foundUser = context.User.Single(x => x.Id == USER_ID);

context.Entry(foundUser).Collection(u =>
u.UserAddresses).Query().Where(userAddress =>
userAddress.Enabled).Load();

请记住,Load() 方法在某些情况下可能会被 EF 忽略:

  1. 如果您将 EF 与延迟加载功能一起使用,则获取您的对象会带来所有在您的类中标记为虚拟的关联集合。因此,通过执行context.User.Single( x => x.id == USER_ID );,您将获得与用户关联的所有用户地址,除非您通过从用户类的属性中删除Virtual 关键字来关闭集合的延迟加载。

  2. 如果您在程序中添加/删除 UserAddresses 集合并调用 context.SaveChanges();在不处理上下文的情况下,下次加载 User 对象时,将从 EF 上下文缓存而不是从 DB(您的最新更改)中加载 UserAddresses 集合。在这种情况下,您需要在从上下文中获取用户之前处置您的上下文并实例化一个新上下文。例如,如果您的用户在您的 UserAddresses 集合中有 5 个项目,并且您禁用其中一项(item.Enabled = false),然后在不处理您的上下文的情况下调用context.SaveChanges(),下次当您从同一上下文中获取用户对象时,它的集合中已经有 5 个项目来自上下文缓存,它忽略了您的 Load() 方法。

PS:

如果满足以下所有条件,则延迟加载功能为开启:

  1. context.Configuration.LazyLoadingEnabled = true;
  2. context.Configuration.ProxyCreationEnabled = true;
  3. UserAddresses 已在您的 User 类中定义为 Virtual。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-18
    • 1970-01-01
    • 2010-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多