我试图使用LINQ获取所有子实体的某个实体的列表,但我使用的方法都没有正常工作。 这是类结构:
public class License {
public virtual Product Product {get; set}
. . . . . .
//some other License properties
. . . . . .
}
public class LicenseUser {
public virtual Account User { get; set;}
public virtual License License { get; set; }
}
我试图获取某些用户的许可证列表,但每个License对象也必须包含Product。我试过的任何查询都返回了许可证列表" null"产品属性中的值 以下是LINQ查询我尝试过的示例:
var licenses = context.LicenseUsers
.Include(lu => lu.License.Product)
.Where(lu => lu.User.Id == 1)
.Select(lu => lu.License)
.ToList();
或
var licenses = context.LicenseUsers
.Include(lu => lu.License).ThenInclude(l => l.Product)
.Where(lu => lu.User.Id == 1)
.Select(lu => lu.License)
.ToList();
我确信这些查询获得的记录包含对Products表的有效引用(ProductId字段不为null)。 我还检查了这个LINQ请求生成的SQL(使用诊断工具)。正如预期的那样,它不包含Products表的JOIN语句。
是否有正确的方法来获得必要的结果?
答案 0 :(得分:3)
这有点违反直觉,但问题是您的Select
正在过滤掉SQL查询包含的内容。
因此,您可能希望强制EF将产品包含在SQL中(使用包含许可证及其产品的匿名对象),然后转换为内存中的License
集合:
var licenses = context.LicenseUsers
.Include(lu => lu.License.Product)
.Where(lu => lu.User.Id == 1)
.Select(lu => new { lic = lu.License, prod = lu.License.Product } )
.AsEnumerable() // Here we have forced the SQL to include the product too
.Select(lu => lu.lic)
.ToList(); // Then we select (locally) only the license for convenience
// (so that our collection is of type License)
// Since the SQL Query actually loaded the products
// the references will be ok
答案 1 :(得分:2)
嗯,我自己也很陌生,但这可能会给你一个想法。
根据this MSDN文章,要急切加载多个级别,您可以尝试这样的事情:
class MyObject {
private OtherObject otherObject;
public OtherObject getOtherObject() {
return otherObject;
}
}
...
myObjects.stream().map(MyObject::getOtherObject).forEach(System.out::println)
并检查其他示例,正如亚历山大所说,Where()在任何情况下应该在Include()之前。
答案 2 :(得分:0)
您需要。选择您想要的属性。在这里,您只需提取许可证属性。尝试将其更改为:
var licenses = context.LicenseUsers
.Include(lu => lu.License.Product)
.Where(lu => lu.User.Id == user.Id)
.Select(lu => new { lu.License, lu.Product })
.ToList();
在这里,您要创建一个新的匿名类型,其中包含您想要附加的两个属性。现在,许可证应该包含这些新的匿名类型的列表,您可以通过
之类的方式访问这些类型Licenses[0].Product
答案 3 :(得分:0)
我们找到了一种解决方法,但在一般情况下可能会导致效率低下。 首先,Include调用正常工作并正确填充LicenseUser对象列表中的License.Product属性。 问题出在最后一次选择呼叫"转换"许可证列表中的LicenseUser对象列表。 解决方案 - 添加" ToList"在Where:
之后打电话var licenses = context.LicenseUsers
.Include(lu => lu.License.Product)
.Where(lu => lu.User.Id == 1)
.ToList()
.Select(lu => lu.License)
.ToList();
(我认为其中一个答案中建议的AsEnumerable调用也适用于此处。)
但是我仍然认为它是Entity Framework Core的LINQ to SQL实现中的一个错误。它可能会看到最后一个Select(它获取LicenseUser的许可证部分)并且忽略了第一个Include请求将结果集添加产品信息(以SQL方式连接到Products表)。