EF6渴望加载相关实体的单一属性

Jer*_*984 7 c# entity-framework

在EF6中,我有一个实体Customer,其导航属性为实体地址.地址实体包含属性"City".

我可以急切地加载Address实体,同时让所有客户都这样:

_dbSet.Customers.Include(customer => customer.Address);
Run Code Online (Sandbox Code Playgroud)

这给了我所有的客户,所有的地址属性都加载了.

当然这样可以正常工作,但我在Address表中唯一需要的是"City"字段,在不需要它们的情况下从持久数据存储(SQL Server)获取所有地址属性并不好.

我尝试了以下方法:

_dbSet.Customers.Include(customer => customer.Address.City);
Run Code Online (Sandbox Code Playgroud)

...但这给了我一个运行时异常:

An unhandled exception of type 'System.InvalidOperationException' occurred in mscorlib.dll

Additional information: A specified Include path is not valid. The EntityType 'MyModel.Address'does not declare a navigation property with the name 'City'.
Run Code Online (Sandbox Code Playgroud)

我理解这一点,因为City只是一个字段,而不是与另一个表/实体的关系.

但是有没有另一种方法可以实现我想要的,或者是最佳实践只包括整个地址实体,即使我只需要城市字段???

我想要的是我可以使用myCustomer.Address.City,而不需要对数据库进行额外的查询,但是当我使用myCustomer.Address.Street时,街道属性不是急切加载的,应该另外从中获取数据库...

Ste*_*ath 5

仅选择您想要的属性,EF 将仅加载需要的属性。

var query = _dbSet.Customers.Include(customer => customer.Address);
var data = query.Select(c => new { Customer = c, City = c.Address.City });
Run Code Online (Sandbox Code Playgroud)

  • 按照 Stef 的建议使用投影是一个很好的解决方案。如果您不想处理匿名类型,您可以创建一个仅包含您只需要的属性的 CustomerSmallInfoDTO。 (3认同)

fli*_*art 4

如果您确实决定在整个代码库中使用相同的实体,那么您可以使用类似于 Stef 提议的方法来解决该问题:

var query = _dbSet.Customers.Include(customer => customer.Address);
var data = query
    .Select(c => new { Customer = c, City = c.Address.City })
    .ToList() //executes the IQueryable, and fetches the Customer and City (only) from the DB
    .ForEach(x => x.Customer.Address = new Address { City = x.City })
    .Select(x => x.Customer)
    .ToList();
Run Code Online (Sandbox Code Playgroud)

我非常赞成 DTO,并且不在整个代码库中使用实体对象,但上面将为您提供一个Customers 列表,其中包含AddressCity填充字段的对象。显然,我假设您的对象具有公共设置器,实体对象通常也具有公共设置器。