2011-08-18 117 views
6

我正在解决保存到数据库之前更新实体的问题,并得到了奇怪的行为。实体框架代码中的奇怪实体更新Code-First

我在ASP.NET MVC 3 Web应用程序中使用实体框架4.1代码优先。这里是模型:

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(); 

有人可以解释,请,这到底是怎么回事呢?尤其是魔法在最后一块代码中的第3和第4行。

更新

我得到DbEntityValidationException:“验证失败的一个或多个实体参见‘EntityValidationErrors’属性的更多详细信息。” 从内部异常:“OriginalValues不能用于添加状态的实体。”

+1

你有没有注意到你在order.RentPrice = _context.Cars.Find(order.CarId)结束了两个分号.RentPrice ;; - >在最后一块代码旁边? – Jack

+1

SaveChanges方法的验证错误是什么?您最初的Create方法中的代码适合我。 – agradl

+0

@Jack,写文章时只是一个错别字。固定。 –

回答

0

你是否在任何地方声明了主键?你应该这样做,要么使用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; } 
} 

或者在你的背景下,您可以用流利的API来声明键,这样

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

EF使用约定而不是配置(它需要 Id属性)。所以,是的,我的数据库有主键。我检查了。以及它如何解释最后一块代码?.. –

0

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

在你最后一段代码(令人惊讶的工作)中,你是否尝试过使用中间变量var而不投射为double?

我也对那个UpdateModel很感兴趣......我使用EF但不是MVC,所以也许它没有任何关系,但是如果它是一个自定义函数,它是做什么的?

18

当你

“验证失败的一个或多个实体。见 ‘EntityValidationErrors’属性的更多细节。“从内部 例外:‘OriginalValues不能用于在新增 国家实体’

这意味着存在错误,如空白或其他约束NOT NULL collumns,通过检查实体验证错误。调试或类似

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); 
    } 
    } 
} 
+0

您是否阅读过我的代码示例? –

+0

嘿,对不起,我没有你的原始问题的解释只是一个提示如何得到什么是从这个错误DbEntityValidationException – John

+0

在我的情况发现我的注册视图模型和身份模型之间的不匹配的数据注释。 – Dreamcasting

0

我肯定会一直年龄前纠正问题,只是想贡献我的2美分。

我也跑与同样的错误消息的问题,我是使用Oracle和EF 5.0。Fin盟友我浪费了超过12小时后得到了一个解决方案。

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

希望有人认为这有用,不会像我一样在排除故障时浪费时间。

干杯,

阿维

1

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... */ 

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