Include路径表达式必须引用在类型上定义的导航属性(使用LINQ选择数据)



我试图使用LINQ选择数据并且我有一个名为";产品";我只想要产品列表中的这些项目

var Owner = db.Owners
.Where(m => m.ID == id)
.Include(m => m.Products.Where(item1 => products.Any(item2 => item2.ProductID == item1.ProductID)).ToList())
.FirstOrDefault();

但我得到了这个错误:

System.ArgumentException:'Include路径表达式必须引用在类型上定义的导航属性。对引用导航属性使用虚线路径,对集合导航属性使用Select操作符。参数名称:路径'

Include用于获取表的完整行,包括主键和外键。

通常,获取一个表的完整行是无效的。例如,假设您有一个包含"学校和学生"的数据库。学校和学生之间存在一对多的关系:每个学校都有零个或多个学生,每个学生都就读于一所学校,即外键所指的学校

如果您获取School[10]及其2000名学生,那么每个学生都将拥有一个值为10的外键SchoolId。如果使用Include并获取完整的Student行,则会将该值传输2000多次10次。真是浪费处理能力!

DbContext有一个ChangeTracker对象。每当您在不使用Select的情况下提取数据时,因此如果您提取完整的行,则提取的行将与它的克隆一起存储在ChangeTracker中。您将获得对克隆的引用(或原始引用,无关紧要(。更改提取数据的属性时,将更改克隆中的值。调用SaveChanges时,ChangeTracker中所有原始文件的所有属性的值都会与克隆中的值进行比较。更改的项目将在数据库中更新。

因此,如果你获取School[10]及其2000名学生,你不仅会获取比以往更多的数据,而且还会将所有这些学生与克隆学生一起存储在ChangeTracker中。如果您为完全不同的事情调用SaveChanges(例如更改学校的电话号码(,则所有学生都会按属性的值与他们的克隆进行比较。

一般规则:

无论何时使用实体框架获取数据,都应始终使用Select,并仅选择实际计划使用的属性。仅提取完整的行,并且仅在计划更新提取的数据时使用Include。

使用Select也可以解决您的问题:

int ownerId = ...
IEnumerable<Product> products = ...
var Owner = db.Owners.Where(owner => owner.ID == ownerId)
.Select(owner => new
{
// Select only the Owner properties that you actually plan to use
Id = owner.Id,
Name = owner.Name,
// get the Products of this Owner that are in variable products
Products = owner.Products
.Where(product => products.Any(p => p.ProductId == product.ProductId)
.Select(product => new
{
// Select only the Product properties that you plan to use
Id = product.Id,
Price = product.Price,
...
// No need to fetch the foreign key, you already fetched the value
// OwnerId = product.OwnerId,
})
.ToList(),
...
})
.FirstOrDefault();

我使用了自动类型(new {...}(。如果你真的想创建所有者和属性,请使用:

var Owner = db.Owners.Where(...)
.Select(owner => new Owner
{
Id = owner.Id,
...
Products = owner.Products.Where(...).Select(product => new Product
{
Id = product.Id,
...
})
.ToList(),
})
.FirstOrDefault();

尝试以下操作:

var productIds = products.Select(x => x.ProductID);
var Owner = db.Owners
.Where(m => m.ID == id)
.Include(m => m.Products.Where(product => productIds.Contains(product.ProductID))
.FirstOrDefault();

最新更新