2011-02-14 112 views
0

我正在使用EF4 CTP5,並且無法將記錄保存回數據庫。我有Contact和ContactType實體。正如帖子標題所述,我在表格之間建立了多對多的導航屬性。EF 4 CTP 5保存多對多導航屬性

問題是驗證ContactType值。 ModelState.IsValid是假的,因爲它是無法傳回值ContactType的id的字符串數組轉換從表單(進入ContactType對象。

POCO的

public partial class Contact 
{ 
    public Contact() 
    {    
     this.ContactTypes = new HashSet<ContactType>(); 
    } 

    // Primitive properties 
    public int ContactId { get; set; } 
    public string ContactName { get; set; } 

    // Navigation properties 
    public virtual ICollection<ContactType> ContactTypes { get; set; } 
} 

public partial class ContactType 
{ 
    public ContactType() 
    { 
     this.Contacts = new HashSet<Contact>(); 
    } 

    // Primitive properties 
    public int ContactTypeId { get; set; } 
    public string Name { get; set; } 

    // Navigation properties 
    public virtual ICollection<Contact> Contacts { get; set; } 
} 

控制器

// 
// GET: /Contact/Edit/5 
public virtual ActionResult Edit(int id) 
{ 
    Contact contact = context.Contacts.Include(c => c.ContactTypes).Single(x => x.ContactId == id); 
    ViewData["ContactTypesAll"] = GetTypesList(); 
    return View(contact); 
} 

// 
// POST: /Contact/Edit/5 
[HttpPost] 
public virtual ActionResult Edit(Contact contact) 
{ 
    if (ModelState.IsValid) 
    { 
     context.Entry(contact).State = EntityState.Modified; 
     context.SaveChanges(); 
     return RedirectToAction("Index"); 
    } 
    ViewData["ContactTypesAll"] = GetTypesList(); 
    return View(contact); 
} 

查看

<div class="field-block"> 
    @Html.LabelFor(model => model.ContactId) 
    @Html.EditorFor(model => model.ContactId, new { fieldName = "ContactId" }) 
    @Html.ValidationMessageFor(model => model.ContactId) 
</div> 
<div class="field-block"> 
    @Html.LabelFor(model => model.OrganizationNameInternal) 
    @Html.EditorFor(model => model.OrganizationNameInternal) 
    @Html.ValidationMessageFor(model => model.OrganizationNameInternal) 
</div> 
<div class="field-block"> 
    @Html.LabelFor(model => model.ContactTypes) 
    @Html.ListBoxFor(modelContactType, 
      new MultiSelectList((IEnumerable<TDAMISObjects.ContactType>)ViewData["ContactTypesAll"], 
       "ContactTypeId", 
       "Name", 
       Model.ContactTypes)) 
    @Html.ValidationMessageFor(model => model.ContactTypes) 
</div> 

ModelState error

ModelState.Values.ElementAt(2).Value 
{System.Web.Mvc.ValueProviderResult} 
    AttemptedValue: "5" 
    Culture: {en-US} 
    RawValue: {string[1]} 

ModelState.Values.ElementAt(2).Errors[0] 
{System.Web.Mvc.ModelError} 
    ErrorMessage: "" 
    Exception: {"The parameter conversion from type 'System.String' to type 'ProjectObjects.ContactType' failed because no type converter can convert between these types."} 

所以它似乎很清楚問題是什麼,但我似乎無法找到解決方案。我曾嘗試ContactType ID的手動轉換成ContactType對象,並將其添加到傳遞到編輯功能的聯繫對象(稱爲「聯繫人」):

contact.ContactTypes.Clear(); 
string[] ids = this.HttpContext.Request.Form["ContactTypes"].Split(','); 
for(int i = 0; i< ids.Length; i++) 
{ 
    int x = Convert.ToInt32(ids[i]); 
    ContactType selectedType = context.ContactTypes.Single(t => t.ContactTypeId == x); 
    contact.ContactTypes.Add(selectedType); 
} 

但錯誤依然存在。我也試過打電話

context.ChangeTracker.DetectChanges(); 

但這並沒有伎倆。我也手動設置ValueProviderResult的值將不會驗證,使用

ModelState.SetModelValue("ContactTypes", val); 

哪些也沒有工作。我覺得我在這裏錯過了一些基本的東西。有任何想法嗎?

謝謝,史蒂夫

回答

0

經過更多的工作後,我發現了一個工作。基本上,我必須忽略驗證錯誤,然後手動刪除現有的聯繫人類型,然後添加用戶選擇的聯繫人類型。我曾嘗試爲Contact.ContactTypes propery構建自定義驗證器,但一個ContactType對象始終傳遞給該方法;我從來沒有看到字符串的數組。無可否認,這是我建立的第一個自定義驗證器,所以也許我錯過了一些東西。

總之,這裏的編輯方法,我結束了:

// 
// POST: /Contact/Edit/5 
[HttpPost] 
public virtual ActionResult Edit(Contact contact) 
{ 
    // clear up ModelState.IsValid for contact type 
    ModelState.Remove("ContactTypes"); 

    if(ModelState.IsValid) 
    { 
     // remove all contact types for contact 
     Contact dummy = context.Contacts.Single(c => c.ContactId == contact.ContactId); 
     if(dummy.ContactTypes.Count > 0) 
     { 
      dummy.ContactTypes.Clear(); 
      context.Entry(dummy).State = EntityState.Modified; 
      context.SaveChanges(); 
     } 
     context.Detach(dummy); 
     context.Contacts.Attach(contact); 

     // add currently selected contact types, then save 
     string[] ids = this.HttpContext.Request.Form["ContactTypes"].Split(','); 
     for(int i = 0; i< ids.Length; i++) 
     { 
      int x = Convert.ToInt32(ids[i]); 
      ContactType selectedType = context.ContactTypes.Single(t => t.ContactTypeId == x); 
      contact.ContactTypes.Add(selectedType);      
     } 
     context.Entry(contact).State = EntityState.Modified; 
     context.SaveChanges(); 

     ViewBag.Message = "Save was successful."; 
    } 

    ViewData["ContactTypes"] = contact.ContactTypes.Select(t => t.ContactTypeId); 
    ViewData["ContactTypesAll"] = GetTypesList();    
    return View(contact); 
} 

我不得不去附着方法添加到我的DbContext類,以及(在CTP 5,這是不暴露):

public void Detach(object entity) 
{ 
    ((System.Data.Entity.Infrastructure.IObjectContextAdapter)this).ObjectContext.Detach(entity); 
}