2014-05-09 61 views
15

我有一個視圖模型,它只封裝了的一些數據庫模型屬性。視圖模型包含的這些屬性是我想要更新的唯一屬性。我希望其他的財產保持其價值。實體框架6.1更新記錄的子集

在我的研究中,我發現this答案似乎是完美的我的需求,但是,儘管我盡了最大的努力,我無法讓代碼按預期工作。

這裏是什麼,我想出了一個孤立的例子:

static void Main() { 
    // Person with ID 1 already exists in database. 

    // 1. Update the Age and Name. 
    Person person = new Person(); 
    person.Id = 1; 
    person.Age = 18; 
    person.Name = "Alex"; 

    // 2. Do not update the NI. I want to preserve that value. 
    // person.NINumber = "123456"; 

    Update(person); 
} 

static void Update(Person updatedPerson) { 
    var context = new PersonContext(); 

    context.Persons.Attach(updatedPerson); 
    var entry = context.Entry(updatedPerson); 

    entry.Property(e => e.Name).IsModified = true; 
    entry.Property(e => e.Age).IsModified = true; 

    // Boom! Throws a validation exception saying that the 
    // NI field is required. 
    context.SaveChanges(); 
} 

public class PersonContext : DbContext { 
    public DbSet<Person> Persons { get; set; } 
} 

public class Person { 
    public int Id { get; set; } 
    [Required] 
    public string Name { get; set; } 
    [Required] 
    public int Age { get; set; } // this is contrived so, yeah. 
    [Required] 
    public string NINumber { get; set; } 
} 

我在做什麼錯?

+1

爲什麼你連接的人提供的解決方案來解決?通常,當我使用實體框架時,我只需檢索記錄,修改其屬性並執行SaveChanges();類似於:Person person = context.People.First(); person.Name =「John」; context.SaveChanges(); – Areks

+0

因爲這實際上需要對數據庫+進行兩次查詢,所以我正在使用通用存儲庫。 –

+1

這不是一個真正的通用存儲庫,但無論如何,@Areks的+1表示。如果你擔心2個查詢,那麼你有其他問題 – mituw16

回答

0

(編輯爲清楚起見)

上下文必須有對象的完整副本來執行業務規則。這隻有在附加對象具有所有必需的屬性時纔會發生,或者在更新之前將部分視圖與完整副本合併。

我相信你想要做的事情在概念上是不可能的:做這樣的更新將需要一個保存的預更改副本或兩個查詢到數據庫,因爲業務層需要完整的對象副本進行驗證。

+0

請引用一個源文件嗎?我*認爲* [這個答案](http://stackoverflow.com/questions/15336248/entity-framework-5-updating-a-record/15339512#15339512)否則表示。 –

+1

並非如此。您只能對修改後的字段執行業務規則。看到我的答案。 – jltrem

+0

@ jltrem-是的,可以禁用記錄驗證,並且您可以按屬性檢查字段級驗證(必需的,範圍等)屬性。但是這種方法不適用於具有記錄級別規則的對象(IValidatableObject或ValidateEntity),兩者都可能要求實體的所有值都通過。無論哪種方式,繞過業務層驗證都需要回退數據庫以確保不會插入錯誤的數據。我想我原來的帖子應該說「在負責任的設計中概念上不可能」? – esmoore68

2

這是導致它不被保存的驗證。您可以使用context.Configuration.ValidateOnSaveEnabled = false;禁用驗證,它將起作用。要驗證特定字段,您可以撥打var error = entry.Property(e => e.Name).GetValidationErrors();。所以你當然可以創建一個'UpdateNameAndAge'方法,它只能強制執行業務規則並將這些屬性標記爲已修改。不需要雙重查詢。

private static bool UpdateNameAndAge(int id, string name, int age) 
    { 
    bool success = false; 

    var context = new PersonContext(); 
    context.Configuration.ValidateOnSaveEnabled = false; 

    var person = new Person() {Id = id, Name = name, Age = age}; 
    context.Persons.Attach(person); 
    var entry = context.Entry(person); 

    // validate the two fields 
    var errorsName = entry.Property(e => e.Name).GetValidationErrors(); 
    var errorsAge = entry.Property(e => e.Age).GetValidationErrors(); 

    // save if validation was good 
    if (!errorsName.Any() && !errorsAge.Any()) 
    { 
     entry.Property(e => e.Name).IsModified = true; 
     entry.Property(e => e.Age).IsModified = true; 

     if (context.SaveChanges() > 0) 
     { 
      success = true; 
     } 
    } 

    return success; 
    }