c# - linq 语句的 DefaultIfEmpty 问题

标签 c# linq ef-core-2.0

有人可以向我解释一下这里出了什么问题吗?我正在使用 Linq to Sql 创建一个非常讨厌的查询。

我遇到的问题是我需要在某些表上进行左连接 (使用 DefaultIfEmpty)我需要从 DefaultIfEmpty(new SomeObject(){...}) 以便我稍后可以再次对其进行连接。

我的问题是 DefaultIfEmpty 总是返回 null。所以我检查了一些虚拟数据作为 POC,它有效

示例

我似乎找不到用于获取下面示例代码的链接,我只是对其进行了一些更改以向 OrderConfirmed 添加额外的连接,因此在运行它时,它的工作原理如下预计。

List<Book> bookList = new List<Book>
{
  new Book{BookID=1, BookNm="DevCurry.com Developer Tips"},
  new Book{BookID=2, BookNm=".NET and COM for Newbies"},
  new Book{BookID=3, BookNm="51 jQuery ASP.NET Recipes"},
  new Book{BookID=4, BookNm="Motivational Gurus"},
  new Book{BookID=5, BookNm="Spiritual Gurus"}
};

List<Order> bookOrders = new List<Order>
{
    new Order{OrderID=1, BookID=1, PaymentMode="Cheque"},
    new Order{OrderID=2, BookID=5, PaymentMode="Credit"},
    new Order{OrderID=3, BookID=1, PaymentMode="Cash"},
    new Order{OrderID=4, BookID=3, PaymentMode="Cheque"},
    new Order{OrderID=5, BookID=5, PaymentMode="Cheque"},
    new Order{OrderID=6, BookID=4, PaymentMode="Cash"}
};

List<OrderConfirmed> orderConfirmed = new List<OrderConfirmed>();


var orderForBooks = from bl in bookList
                    join ordr in bookOrders on bl.BookID equals ordr.BookID into a
                        from ordr in a.DefaultIfEmpty(new Order {BookID = -1, OrderID = 12, PaymentMode = "Cash Test" }) // return default value
                    join confirmed in orderConfirmed on ordr.OrderID equals confirmed.OrderID into c
                        from confirmed in c.DefaultIfEmpty(new OrderConfirmed() { OrderID = 12, Description = "Is this working"}) // no values in orderconfirmed so returning new object
                    select new
                               {
                                   bl,
                                   ordr,
                                   confirmed
                    };

因此,知道我正在尝试执行的操作应该有效,在我的实际代码中,DefaultIfEmpty 始终为 null。我说这应该有效吗? 也许需要注意的是我正在使用 EFCORE

var formData = 
 await (from ccf in this.context.Set<BureauCountryCustomForm>()
          join ccfa in this.context.Set<EmployeeCustomFormAttributeHeader>() on ccf.BureauCountryFormId equals ccfa.BureauCountryFormId into ccfaJoin
          from ccfa in ccfaJoin.DefaultIfEmpty(new EmployeeCustomFormAttributeHeader()
                                                   {
                                                       HeaderId = -1,
                                                       BureauCountryFormId = 3,
                                                       CompanyFormId = -1,
                                                       EmployeeId = 1
                                                   })
          join cca in this.context.Set<BureauCountryCustomFormAttribute>() on ccf.BureauCountryFormId equals cca.BureauCountryFormId
          join edv in this.context.Set<EmployeeCustomFormValue>() on
              new { AttributeId = (int?)cca.BureauCountryFormAttributeId, HeaderId = (int?)ccfa.HeaderId } equals
              new { AttributeId = (int?)edv.FormAttributeId, HeaderId = (int?)edv.HeaderId } into edvJoin
          from edv in edvJoin.DefaultIfEmpty(new EmployeeCustomFormValue()
                                                 {
                                                     HeaderId = -1,
                                                     FormAttributeId = -1
                                                 })
          where ccf.CountryId == countryId && ccf.EmployeeLevel == true && ccfa.EmployeeId == employeeId
          select new { ccf, ccfa, cca, edv }).GroupBy(g => new { g.ccf.BureauCountryFormId, g.ccfa.HeaderId })
.Select(
_ => new CustomFormData
{
    Keys = new[] { _.Key.BureauCountryFormId, _.Key.HeaderId },
    FormName = _.First().ccf.FormName,
    EffectiveDate = _.First().ccfa.EffectiveDate,
    FormDataFields = _.Select(
                 f => new CustomFormDataField
                 {
                     AttributeId = f.cca.BureauCountryFormAttributeId,
                     FieldLabel = f.cca.FieldLabel,
                     IsMandatory = f.cca.IsMandatory,
                     FieldValue = f.edv.FieldValue,
                     ControlTypeId = (long)f.cca.ControlTypeId,
                     DropdownValues = f.cca.DropdownValues,
                     Order = f.cca.AttOrderNo,
                     ValidationRule = f.cca.ValidationRule,
                     ValidationExpression = f.cca.ValidationExpression
                 }).ToList()
}).ToListAsync();

最佳答案

问题出在:

from ccfa in ccfaJoin.DefaultIfEmpty(new EmployeeCustomFormAttributeHeader())

这样的查询构造只能用于数据库集或查询等集合,而不是 DefaultIfEmpty,但它是 IEnumerable,但 EF Core 将其视为单个值(如果没有匹配,则在 sql 查询结果中实际上为 null),无论它在哪里使用过。

您应该将其更改为:

let ccfa = ccfaJoin.DefaultIfEmpty(new EmployeeCustomFormAttributeHeader())

它应该按预期工作。

关于c# - linq 语句的 DefaultIfEmpty 问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49372314/

相关文章:

c# - 如何实现邀请码与其他用户共享资源?

c# - LINQ to SQL - 如何高效地对多个条件执行 AND 或 OR 搜索

linq - 如何从查询中获取前 1 条记录

c# - .NET 标准的 System.Data.SqlClient 出错

entity-framework - 如何阻止EF Core索引所有外键

c# - 在分配控制台之前调用 Console.WriteLine

c# - 每次打开应用程序窗口(其他进程)时如何执行一些代码?

c# - Mkbundle Mono Assembly 绑定(bind)重定向

c# - 检查字符串是否排序

c# - AutoFac/.NET Core - 注册 DBcontext