Entity Framework Core 2.1在左连接时抛出了ArgumentException异常

8

我最近将我的项目从.NET Core 2.0升级到了2.1。我使用Entity Framework Core并且有几个包含左连接的LINQ表达式。以下代码是一个例子:

var tickets = (from ticket in dbContext.Tickets
               join member in dbContext.Members on ticket.MemberID equals member.ID into memberLEFT
               from member in memberLEFT.DefaultIfEmpty()
               join memberType in dbContext.MemberTypes on member.MemberTypeID equals memberType.ID into memberTypeLEFT
               from memberType in memberTypeLEFT.DefaultIfEmpty()
               select memberType)
              .ToList();

如果在.NET Core 2.0中,此行将不会出现异常。但在.NET Core 2.1中,它会抛出以下ArgumentException:
System.ArgumentException:“字段'Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor+TransparentIdentifier`2[Microsoft.EntityFrameworkCore.Storage.ValueBuffer,System.Collections.Generic.IEnumerable`1[Microsoft.EntityFrameworkCore.Storage.ValueBuffer]].Inner'未定义于类型'Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor+TransparentIdentifier`2[Microsoft.EntityFrameworkCore.Storage.ValueBuffer,Microsoft.EntityFrameworkCore.Storage.ValueBuffer]'。”
如果我更改LINQ以执行内部连接而不是左连接,则执行没有任何问题。但是,连接必须是左连接,所以我不能只更新所有代码以执行内部连接。
请问有人知道为什么EF Core 2.1在执行左连接时会抛出ArgumentExecptions,并如何解决这个问题?
3个回答

9

工具 > 选项中勾选启用仅调试我的代码

输入图片说明


1
这并不是有帮助的。 - Robert Perry
2
@RobertPerry,错误出现的原因是你正在调试EfCore内部库。如果你禁用它,就会得到与你相关的错误。此外,这是一个EfCore内部错误,他们将在3.0版本中解决。 - Mohammad Hossein Amri
1
这解决了我的问题。谢谢你。你知道与此相关的错误编号吗? - dgxhubbard
很高兴你觉得它有用,但很抱歉我不记得它在哪里了,但是在问题跟踪器中有一个相同的错误,并且他们为3.0版本设置了一个里程碑。 - Mohammad Hossein Amri
这一定是正确答案,我曾经遇到过同样的问题。但因为设置没有被选中,我一直收到那个异常。当我检查了它后,异常消失了。原来这个异常与 EF Core 有关,不影响应用程序的流程。 - Nadeem Khoury

2
我不确定为什么你要自己创建联接,而不是使用EF关系模型。我拿了你的例子并稍微修改了一下。 模型:
public class Ticket
{
    [Key]
    public int ID { get; set; }

    [Required]
    [StringLength(200)]
    public string Description { get; set; }

    public int? MemberID { get; set; }

    [ForeignKey(nameof(MemberID))]
    public Member Member { get; set; }
}

public class Member
{
    [Key]
    public int ID { get; set; }

    [Required]
    [StringLength(200)]
    public string Description { get; set; }

    public int? MemberTypeID { get; set; }

    public ICollection<Ticket> Tickets { get; set; }
    [ForeignKey(nameof(MemberTypeID))]
    public MemberType MemberType { get; set; }
}

public class MemberType
{
    [Key]
    public int ID { get; set; }

    [Required]
    [StringLength(200)]
    public string Description { get; set; }
}

要定义外连接,只需将外键设置为可为空。

当您创建了这样的模型后,您只需在查询中包含属性即可:

Tickets = (from t in _dbContext.Tickets
              .Include(t => t.Member)
                  .ThenInclude(m => m.MemberType)
            select t).ToList();

生成的 SQL 如下所示:
SELECT [t].[ID], [t].[Description], [t].[MemberID], [t.Member].[ID], [t.Member]. 
    [Description], [t.Member].[MemberTypeID], [t.Member.MemberType].[ID], 
    [t.Member.MemberType].[Description]
FROM [Tickets] AS [t]
LEFT JOIN [Members] AS [t.Member] ON [t].[MemberID] = [t.Member].[ID]
LEFT JOIN [MemberTypes] AS [t.Member.MemberType] ON [t.Member].[MemberTypeID] = 
    [t.Member.MemberType].[ID]

希望这能解决你的问题。

1
是的!又一位导航属性布道者! - Gert Arnold
谢谢您的建议。我已经按照您所说的定义了我的模型,并且在我的代码中经常使用Includes和ThenIncludes。我认为在可能的情况下使用连接而不是Includes/ThenIncludes是更好的实践,因为我认为生成的SQL查询方式更有效率。然而,从您的示例生成的SQL查询来看,Includes/ThenIncludes与编写连接一样(如果不是更)高效。我将开始使用Includes/ThenIncludes,并查看是否有任何明显的性能差异,如果没有,我将尽可能使用它们。 - Courier
你不需要使用ForeignKey属性或ID属性。EF足够智能,当你拥有另一个自定义类型的属性时,它就知道你想要一个外键。 - Paw Baltzersen
这个答案几乎完全符合我的想法 - 但是我被抢先了!我唯一建议的另一件事是远离DataAnnotationAttributes,改用EF流畅配置。它更加简洁。 - Robert Perry

1

对我来说,在这里找到的最好解决方案是:[https://dev59.com/jFQK5IYBdhLWcg3wT-Tf#58017017],来自stackoverflow用户:Hakan Çelik MK1


使用Visual Studio 2019(我假设2017也一样)可以仅针对System.Linq.Expressions禁用此异常。

操作步骤如下:

  • 打开异常设置窗口。调试 -> 窗口 -> 异常设置 (Ctrl+Alt+E)
  • 在窗口右上角有一个搜索框,输入“System.ArgumentException”
  • 您将在窗口中看到该异常已列出,请右键单击它并从菜单中选择“编辑条件”
  • 编辑条件允许您设置调试器在抛出异常时断点的条件
  • 从左到右选择模块名称,选择不等于,并在右侧的编辑框中键入“System.Linq.Expressions.dll” 点击确定并关闭窗口

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接