2011-08-18 119 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中,因爲受影響的行數用於檢測現有的已更改數據。