var result = this._databaseContext.MyCustomers.AsNoTracking()
.Where(p => p.customerActive.HasValue && p.customerActive.Value)
.Include(p => p.MailAddress)
.Select(c => new CustomerModel
{
Id = c.Id,
Name = c.Name,
Address = c.MailAddress
}我想将'MailAddress‘对象转换为'Address’对象。我已经检查了Linq中的'select‘方法,但它只允许映射来自IEnumerable的对象。
发布于 2020-06-23 14:43:03
大多数LINQ方法返回IEnumerable
您知道,IEnumerable<...> (和IQueryable<...>)表示一个接一个地访问一系列相似元素的可能性。它不像列表或数组那样表示这个序列本身。
如果研究IEnumerable<...>,就会发现获取元素是使用GetEnumerator完成的,并反复调用MoveNext() / Current,直到处理完所需的元素。
IEnumerable<CustomerModel> customers = ...
IEnumerator<CustomerModel> customerEnumerator = customers.GetEnumerator();
while (customerEnumerator.MoveNext())
{
// There is next element in the sequence
CustomerModel nextElementToProcess = customerEnumerator.Current();
Process(nextElementToProcess);
}这是大量的代码,因此foreach应运而生。Foreach做你上面看到的:它是枚举器,并创建一个while(enumerator.MoveNext())。
如果仔细观察LINQ方法,您会发现有两种LINQ方法:返回IEnumerable<...> (或IQueryable<...>)的方法和其他方法。第一组中的方法返回“逐个获取元素的可能性”,如上所述,其他组返回元素:有时像列表/数组那样的序列,有时像Count这样的其他元素。
第一组中的方法的描述都提到它们使用延迟执行。这意味着:它不是序列本身,而是获取元素的可能性。一旦你使用GetEnumerator()和MoveNext()命令,代码就会执行。
如果你读了上面的内容,你会知道你的查询还没有被执行。它表示获取元素的可能性。您需要第二个组中的方法或foreach来执行查询。
显然,您需要0个或1个元素。在这种情况下,最后一个方法可以是FirstOrDefault()。即使您需要更多元素,但只对第一个元素感兴趣,也可以使用FirstOrDefault()。
因此,在连接LINQ方法时,应该始终只连接返回IEnumerable<...>的元素。只有最后一个应该是第二组中的方法:ToList()、Count()、Any()等。
回到你的问题
显然,您有一个包含客户的表和一个包含EmailAddresses的表。在Customers和EmailAddresses之间似乎存在一对多的关系:每个客户都有零个或一个EmailAddresses,每个EmailAddress只属于一个客户,即外键引用的客户。
您似乎需要所有活动客户的几个属性,包括他们的第一个EmailAddress,或者如果该客户没有EmailAddress,则为null。
您是对的:要选择一个类的一个或多个属性,请使用Select。结果是一个序列。您只对该序列的第一个元素感兴趣:添加FirstOrDefault()
使用实体框架时,请始终使用选择,并且只选择计划使用的属性。仅当您计划更改/更新包含的数据时才使用
Include。
原因是,Include将获取所有属性,包括您不打算使用的属性,或者您知道其值的属性。Customer 10的每个EmailAddress都有一个值为10的外键CustomerId。因此,如果您使用Customer 10的EmailAddresses来获取他,那么您已经知道EmailAddress.CustomerId的值是什么。
我要将'MailAddress‘对象转换为'Address’对象。
var result = this._databaseContext.MyCustomers.AsNoTracking()
.Where(customer => customer.customerActive.HasValue && customer.customerActive.Value)
.Select(customer => new CustomerModel
{
Id = customer.Id,
Name = customer.Name,
Address = customer.MailAddresses.FirstOrDefault(),
})
// result is the potential to fetch the elements. To actually fetch all these Customers add:
.ToList();可能是Customer.MailAddresses包含与CustomerModel.Address不同的类型,在这种情况下使用了额外的Select。
.Select(customer => new CustomerModel
{
...
Address = customer.MailAddresses.Select(mailAddress =>
... // create a value that can be assigned to CustomerModel.Address
)
.FirstOrDefault(),
})
.ToList();https://stackoverflow.com/questions/62526299
复制相似问题