EF 4 CTP 5 保存多对多导航属性
我正在使用 EF4 CTP5,但在将记录保存回数据库时遇到问题。我有 Contact 和 ContactType 实体。正如帖子标题所述,我在表之间设置了多对多导航属性。
问题在于验证 ContactType 值。 ModelState.IsValid 为 false,因为它无法将从表单传回的值(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 错误
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();
但确实如此 。我还手动设置了无法验证的值,
ModelState.SetModelValue("ContactTypes", val);
我觉得我在这里缺少一些基本的东西,
谢谢,史蒂夫?
I'm using EF4 CTP5 and am having trouble saving records back to the database. I have Contact and ContactType entities. As the post title states, I have set up a many-to-many navigation property between the tables.
The problem is with validating the ContactType values. ModelState.IsValid is false because it's unable to convert the values passed back from the form (a string array of ContactType id's into ContactType objects.
POCO's
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; }
}
Controller
//
// 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);
}
View
<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."}
So it seems pretty clear what the problem is, but I can't seem to find the solution. I have tried to manually convert the ContactType id's into ContactType objects, and adding them to the Contact object passed into the Edit function (called 'contact'):
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);
}
but the error persists. I've also tried calling
context.ChangeTracker.DetectChanges();
but that did not do the trick. I also manually set the ValueProviderResult for the value that will not validate, using
ModelState.SetModelValue("ContactTypes", val);
Which also did not work. I feel like I'm missing something basic here. Any ideas?
Thanks, Steve
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
经过更多的工作后,我找到了解决方法。基本上,我必须忽略验证错误,然后手动删除现有的 ContactType,然后添加用户选择的 ContactType。我确实尝试为 Contact.ContactTypes 属性构建一个自定义验证器,但始终将 ContactType 对象传递给该方法;我从未见过字符串数组。不可否认,这是我构建的第一个自定义验证器,所以也许我遗漏了一些东西。
无论如何,这是我最终得到的 Edit 方法:
我还必须向我的 DBContext 类添加 Detach 方法(在 CTP 5 中这不会公开):
Well after more work on this, I found a work around. Basically, I had to ignore the validation errors, then manually remove existing ContactTypes, then add in ones selected by the user. I did try to build a custom validator for the Contact.ContactTypes propery, but a ContactType object was always passed in to that method; I never saw the array of strings. Admittedly, that was the first custom validator I have built, so perhaps I was missing something.
Anyway, here's the Edit method I ended up with:
I had to add a Detach method to my DBContext class as well (in CTP 5 this is not exposed):