使用 Linq 每次迭代选择多个项



每次迭代,此查询为每个填充的地址创建一个电子邮件收件人。 没有多次迭代可以完成吗?

var addedRecipients = (from oldRecip in oldEmailRecipients
                        where !string.IsNullOrWhiteSpace(oldRecip.EmailAddress1)
                        select new EmailRecipient
                            {
                                UserName = oldRecip.UserName,
                                EmailAddress = oldRecip.EmailAddress1
                            }
                ).Union(from oldRecip in oldEmailRecipients
                        where !string.IsNullOrWhiteSpace(oldRecip.EmailAddress2)
                        select new EmailRecipient
                            {
                                UserName = oldRecip.UserName,
                                EmailAddress = oldRecip.EmailAddress2
                            });

您可以使用SelectMany扩展方法:

var addedRecipients = oldEmailRecipients.SelectMany(e=>
                                         {
                                          var result= new List<EmailRecipient>();
                                          if(!string.IsNullOrWhiteSpace(e.EmailAddress1))
                                          {
                                             result.Add(new EmailRecipient
                                                            {
                                                              UserName = e.UserName,
                                                              EmailAddress = e.EmailAddress1
                                                            });
                                          }
                                          if(!string.IsNullOrWhiteSpace(e.EmailAddress2))
                                          {
                                             result.Add(new EmailRecipient
                                                            {
                                                                UserName = e.UserName,
                                                                EmailAddress = e.EmailAddress2
                                                            });
                                          }
                                          return result;
                                         });

更新

我上面展示的解决方案仅适用于 Linq to Objects。您的评论表明我正在使用 EF。一个简单的解决方案是在SelectMany切换到 Linq to Object 之前调用AsEnumerable方法,但如果不先筛选收件人,这可能会损害您的性能。

另一种解决方案可能是在调用SelectMany之前仅从服务器中选择首先需要的数据,以便在这种情况下不加载不需要的其他列:

...Where(...)
  .Select(r=>new{UserName=r.UserName,
                 EmailAddress1=r.EmailAddress1,
                 EmailAddress2=r.EmailAddress2 })
  .AsEnumerable()
  .SelectMany(...);

坚持使用查询语法,并确保只处理具有非 null/空格EmailAddress1或非 null/空格EmailAddress2 oldEmailRecipients项:

var addedRecipients =
    from oldEmail in oldEmailRecipients
    let hasEmail1 = !string.IsNullOrWhiteSpace(oldEmail.EmailAddress1)
    let hasEmail2 = !string.IsNullOrWhiteSpace(oldEmail.EmailAddress2)
    where hasEmail1 || hasEmail2
    let emailUserNameCombos = hasEmail1 && hasEmail2
        ? new[]
        {
            new {Email = oldEmail.EmailAddress1, oldEmail.UserName},
            new {Email = oldEmail.EmailAddress2, oldEmail.UserName}
        }
        : hasEmail1
            ? new[] {new {Email = oldEmail.EmailAddress1, oldEmail.UserName}}
            : new[] {new {Email = oldEmail.EmailAddress2, oldEmail.UserName}}
    from emailUsername in emailUserNameCombos
    select new EmailRecipient 
        {
            UserName = emailUsername.UserName,
            EmailAddress = emailUsername.Email
        };

您可以构建一个内联数组来添加两封电子邮件,并使用 SelectMany 将它们展平。

var addedRecipients = from oldRecip in oldEmailRecipients
    let emails =
        new[] {oldRecip.EmailAddress1, oldRecip.EmailAddress2}.Where(e => !string.IsNullOrWhiteSpace(e))
    from email in emails
    where emails.Any()
    select new EmailRecipient
    {
        UserName = oldRecip.UserName,
        EmailAddress = email
    };

当您的EmailRecipient有两个以上的电子邮件地址时,您可以这样做:

// Just building a pseudo dataclass
List<Recipient> oldEmailRecipients = Enumerable.Range(1, 10).Select(item => new Recipient()
{
    Name = "Recipient" + item,
    EmailAddress1 = "pseudo" + item + "@gmail.com",
    EmailAddress2 = "pseudo" + (item + 1) + "@gmail.com",
    //EmailAddress3 = "pseudo" + (item + 2) + "@gmail.com",
    EmailAddress3 = "",
    EmailAddress4 = "pseudo" + (item + 3) + "@gmail.com",
} ).ToList( )
// create anonymous object for each recipient and a list of valid adresses
var query = from mailRecipients in oldEmailRecipients
            select new
            {
                Name = mailRecipients.Name,
                Addresses = new List<string>()
                {
                    mailRecipients.EmailAddress1,
                    mailRecipients.EmailAddress2,
                    mailRecipients.EmailAddress3,
                    mailRecipients.EmailAddress4
                }.Where(item => string.IsNullOrEmpty( item ) == false )
            };
// create an EmailRecipient for each valid combination
var final = from item in query
            from address in item.Addresses
            select new EmailRecipient
            {
                Name = item.Name,
                Address = address
            };

最新更新