首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何在LinQ中映射单个对象而不是IEnumerable

如何在LinQ中映射单个对象而不是IEnumerable
EN

Stack Overflow用户
提问于 2020-06-23 10:20:44
回答 3查看 492关注 0票数 0
代码语言:javascript
复制
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的对象。

EN

Stack Overflow用户

发布于 2020-06-23 14:43:03

大多数LINQ方法返回IEnumerable

您知道,IEnumerable<...> (和IQueryable<...>)表示一个接一个地访问一系列相似元素的可能性。它不像列表或数组那样表示这个序列本身。

如果研究IEnumerable<...>,就会发现获取元素是使用GetEnumerator完成的,并反复调用MoveNext() / Current,直到处理完所需的元素。

代码语言:javascript
复制
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’对象。

代码语言:javascript
复制
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。

代码语言:javascript
复制
.Select(customer => new CustomerModel
{
    ...
    Address = customer.MailAddresses.Select(mailAddress =>
          ... // create a value that can be assigned to CustomerModel.Address
          )
          .FirstOrDefault(),
})
.ToList();
票数 0
EN
查看全部 3 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62526299

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档