EF 4 CTP 5, сохраняющий свойство навигации многие ко многим - PullRequest
0 голосов
/ 14 февраля 2011

Я использую EF4 CTP5 и у меня проблемы с сохранением записей обратно в базу данных.У меня есть объекты Contact и ContactType.Как говорится в заголовке записи, я установил свойство навигации «многие ко многим» между таблицами.

Проблема заключается в проверке значений ContactType.ModelState.IsValid имеет значение false, поскольку не может преобразовать значения, переданные обратно из формы (строковый массив идентификаторов ContactType в объекты 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 в объекты ContactType и добавить их в объект Contact, передаваемый в функцию Edit (называемую «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);
}

, но ошибка сохраняется. Я также попытался вызвать

context.ChangeTracker.DetectChanges();

но это не сработало. Я также вручную установил ValueProviderResult для значения, которое не будет проверяться, используя

ModelState.SetModelValue("ContactTypes", val);

, что также не сработало. Я чувствую, что я 'Мне здесь не хватает чего-то простого. Есть идеи?

Спасибо, Стив

1 Ответ

0 голосов
/ 16 февраля 2011

Что ж, после дополнительной работы над этим я нашел обходной путь.По сути, мне пришлось игнорировать ошибки проверки, затем вручную удалить существующие типы контактов, а затем добавить те, которые выбрал пользователь.Я попытался создать собственный валидатор для свойства Contact.ContactTypes, но объект ContactType всегда передавался этому методу;Я никогда не видел массив строк.По общему признанию, это был первый пользовательский валидатор, который я создал, так что, возможно, я что-то упустил.

В любом случае, вот метод Edit, с которым я закончил:Также отсоедините метод от моего класса DBContext (в CTP 5 это не раскрывается):

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