【问题标题】:Strange entity updating in Entity Framework Code-FirstEntity Framework Code-First 中的奇怪实体更新
【发布时间】:2011-10-29 23:12:27
【问题描述】:

我正在解决保存到数据库之前更新实体的问题并得到奇怪的行为。

我在 ASP.NET MVC 3 Web 应用程序中使用 Entity Framework 4.1 Code-First。这是模型:

public class Order
{
    public int OrderId { get; set; }
    public int CarId { get; set; }
    public DateTime BeginRentDate { get; set; }
    public DateTime EndRentDate { get; set; }
    public decimal RentPrice { get; set; }
    public virtual Car Car { get; set; }
}

public class Car
{
    public int CarId { get; set; }
    public string Brand { get; set; }
    public string Model { get; set; }
    public string NumberPlate { get; set; }
    public decimal RentPrice { get; set; }
}

每辆车都有一个 RentPrice。创建价格时,应将此价格复制到 Order 的 RentPrice。汽车是由用户选择的,所以最初 Order.RentPrice 为 0。

这里我要复制价格值:

[HttpPost]
public ActionResult Create(Order order)
{
    order.RentPrice = _context.Cars.Find(order.CarId).RentPrice;

    if (ModelState.IsValid)
    {
        _context.Orders.Add(order);
        _context.SaveChanges();
        return RedirectToAction("Index");
    }

    return View(order);
}

由于SaveChanges 上的错误,该实体存在验证错误,因此无法正常工作。好的。我发现需要先调用UpdateModel(order); 然后更改值。

所以我有什么。工作代码:

_context.Orders.Add(order);
UpdateModel(order);
order.RentPrice = 777;
_context.SaveChanges();

工作代码:

_context.Orders.Add(order);
UpdateModel(order);
order.RentPrice = _context.Cars.Find(order.CarId).RentPrice;
_context.SaveChanges();

工作代码(!):

_context.Orders.Add(order);
UpdateModel(order);
var t = (double)_context.Cars.Find(order.CarId).RentPrice;
order.RentPrice = (decimal)t;
_context.SaveChanges();

有人可以解释一下,这里发生了什么吗?特别是magic在最后一段代码的第3行和第4行。

更新

我收到DbEntityValidationException:“一个或多个实体的验证失败。有关更多详细信息,请参阅“EntityValidationErrors”属性。” 来自内部异常:“OriginalValues 不能用于处于已添加状态的实体。”

【问题讨论】:

  • 你注意到你有两个分号在 order.RentPrice = _context.Cars.Find(order.CarId).RentPrice;; --> 在最后一段代码的旁边?
  • SaveChanges 方法的验证错误是什么?您最初的 Create 方法中的代码对我来说很好。
  • @Jack,只是写帖子时的错别字。固定。
  • @shiznit123,我添加了异常,我得到了所有不工作的代码示例。
  • 您的 post 操作的第一个代码 sn-p 是否也会给出相同的验证错误“原始值不能用于处于已添加状态的实体”?我不敢相信......如果不是,这段代码中的验证错误是什么?我相信这是重要的提示。

标签: c# entity-framework asp.net-mvc-3 ef-code-first


【解决方案1】:

当你得到

“一个或多个实体的验证失败。请参阅 'EntityValidationErrors' 属性以获取更多详细信息。”来自内部 例外:“原始值不能用于已添加的实体 状态。”

表示存在NOT NULL列为空白或其他约束等错误,通过调试或类似检查实体验证错误

try{
...
catch ( DbEntityValidationException ex )
   {
foreach ( var validationErrors in ex.EntityValidationErrors )
    {
     foreach ( var validationError in validationErrors.ValidationErrors )
     {
      System.Diagnostics.Trace.TraceInformation( "Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage );
     }
    }
}

【讨论】:

  • 嘿抱歉我没有解释你原来的问题只是一个提示如何从那个 DbEntityValidationException 得到错误的真正原因
  • 在我的例子中发现我的注册视图模型和身份模型之间的数据注释不匹配。
【解决方案2】:

OriginalValues 不能用于处于已添加状态的实体。

可以通过确保在模型中将非身份主键字段指定为未生成来进行更正。

modelBuilder
    .Entity<T>()
    .HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
    // this can also be achieved using attributes on the entity.

当你有上下文时,这个错误实际上是不言自明的,否则就令人困惑。数据库为插入生成两条语句,第二条是:

SELECT [PrimaryKeyId]
FROM [dbo].[Entity]
WHERE @@ROWCOUNT > 0 AND [PrimaryKeyId] = scope_identity()
/* SP:StmtCompleted... */

此语句不会为 non identity 列返回任何行。因此,OriginalValues 在添加状态下将保持不变。这也解释了为什么此异常被包装在 OptimisticConcurrencyException 中,因为受影响的行数用于检测现有的更改数据。

【讨论】:

    【解决方案3】:

    您是否在任何地方声明了主键?您应该使用 FluentAPI 或这样的属性来做到这一点:

    public class Order
    {
        [Key]
        public int OrderId { get; set; }
        public int CarId { get; set; }
        public DateTime BeginRentDate { get; set; }
        public DateTime EndRentDate { get; set; }
        public decimal RentPrice { get; set; }
        public virtual Car Car { get; set; }
    }
    
    public class Car
    {
        [Key]
        public int CarId { get; set; }
        public string Brand { get; set; }
        public string Model { get; set; }
        public string NumberPlate { get; set; }
        public decimal RentPrice { get; set; }
    }
    

    或者在你的上下文中,你可以使用 Fluent API 来声明密钥,像这样

    builder.Entity<Car>().HasKey(x=>x.CarId);
    builder.Entity<Order>().HasKey(x=>x.OrderId);
    

    【讨论】:

    • EF 使用约定优于配置(它需要 Id 属性)。所以,是的,我的数据库有主键。我检查了。以及它如何解释最后一段代码?..
    【解决方案4】:

    我有一个想法,但更多的是猜测......也许当你进入那个 Create 函数时,上下文已经知道那个 Order 了?如果是这样,尝试再次重新添加它可能会给您该错误。

    在您的最后一段代码(令人惊讶的工作)中,您是否尝试过使用中间变量而不强制转换为 double?

    我也对 UpdateModel 很感兴趣...我使用 EF 而不是 MVC,所以可能与它无关,但如果它是自定义函数,它有什么作用?

    【讨论】:

      【解决方案5】:

      我相信这个问题早在很久以前就已经解决了,只是想贡献我的 2 美分。

      我也遇到了同样的错误消息,我使用的是 Oracle 和 EF 5.0。在浪费了12个多小时后,我终于得到了解决方案。

      对我来说,我试图插入值的表上的用户缺乏权限,并且错误消息绝对没有提示实际权限问题,这真的很奇怪。

      希望有人觉得这很有用,不要像我一样浪费时间进行故障排除。

      干杯,

      视频

      【讨论】:

        猜你喜欢
        • 2014-11-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-05-15
        • 2013-01-01
        • 1970-01-01
        相关资源
        最近更新 更多