【问题标题】:Grouping by primary key of a left-joined entity in Entity Framework causes exception在实体框架中按左连接实体的主键分组导致异常
【发布时间】:2018-01-07 07:47:03
【问题描述】:

我有一个包含两个实体的简单模型:

public class Product
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    [StringLength(150)] public string Name { get; set; }
}

public class Order
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public decimal? Amount { get; set; }

    public int? ProductId { get; set; }

    [ForeignKey(nameof(ProductId))] public Product Product { get; set; }
}

public class OrderContext : DbContext
{
    public DbSet<Product> Products { get; set; }

    public DbSet<Order> Orders { get; set; }
}

如您所见,OrderProduct 之间有一个可为空的外键。 我用这些记录初始化了数据库:

using (var db = new OrderContext())
{
    var p = new Product {Name = "Test"};
    db.Products.Add(p);

    db.Orders.Add(new Order {Product = p, Amount = 1});
    db.Orders.Add(new Order {ProductId = null, Amount = 2});

    db.SaveChanges();
}

当我执行以下查询时,会引发 InvalidOperationException

var result = db.Orders.GroupBy(x => x.Product.Id).ToArray();

异常信息是:

System.InvalidOperationException:转换为值类型“System.Int32”失败,因为具体化值为 null。结果类型的泛型参数或查询必须使用可为空的类型。

这是 EF 中的错误吗?如何解决?

--

这不是The cast to value type 'Int32' failed because the materialized value is null 的重复。尽管有相同的异常信息,但问题的原因和解决方法却完全不同。提到的问题是关于聚合一个空集合。但这是关于按另一个左连接表的主键进行分组。我不知道这两个问题为什么会如此相似!

【问题讨论】:

  • 会有没有产品或金额的订单吗?如果不是,为什么这些道具可以为空?
  • 尝试从 x =&gt; x.Product.Id 更改为 x =&gt; x.ProductId - 这可能会解决问题,虽然我同意,但 EF 应该能够处理这种情况
  • 执行以下操作... var orders = db.Orders.ToArray();var products = db.Products.ToArray(); ?
  • “我不知道这两个问题为什么会如此相似!” - 因为它们只是同一个潜在问题的两种不同表现形式,正如另一个问题的答案所解释的那样。我暂时不会再次关闭它,因为您写的是“问题的原因和解决方案完全不同”。其他问题的公认答案应该也适合您。你真的是说db.Orders.GroupBy(x =&gt; (int?)x.Product.Id) 仍然给你一个例外吗?
  • @Khodaie 我不猜测他们可能只是基于相同的异常消息在这里有相同的潜在问题,我是说他们在这里肯定有相同的潜在问题,那就是C# 类型规则和 SQL 可空性规则在某些情况下具有根本不同的行为,C# 类型规则在编译时使用,但 SQL 可空性规则在运行时使用。由于您现在确认其他问题的答案实际上在这里有效,与您的编辑建议相反,是否可以再次关闭此问题?

标签: c# entity-framework


【解决方案1】:

听起来您在 EF 期望不可为空的 int32 的 db 中有一个空值。对于 Order 和 Product 模型上的每个 int 属性,您需要检查它们对应的数据库列是否不可为空并且是 int 类型。

你也可以试试这个来消除空值...

var result = db.Orders.Where(o => o.Product.Id.HasValue).GroupBy(x => x.Product.Id.Value).ToArray();

如果您需要在结果中包含 null,那么您需要将 null 替换为其他内容(例如 -1)...

var result = db.Orders.GroupBy(x => x.Product?.Id ?? -1).ToArray();

【讨论】:

  • 此解决方案从结果中消除空值。
  • @Khodaie 是的,我相信我在答案中这么说。您应该编辑您的问题以明确表明您需要在结果中包含 null 。无论如何,我添加了一种可能的方法来包含空值。
猜你喜欢
  • 1970-01-01
  • 2011-07-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-18
  • 2013-01-19
  • 1970-01-01
相关资源
最近更新 更多