Обновление свойств навигации в DbContext EF 4.1 - PullRequest
0 голосов
/ 19 июля 2011

После исследования всего дня и ночи у меня есть кое-что, что в данный момент работает. Однако я не уверен, что я действительно понимаю, что происходит со свойствами навигации и связями сущностей, поэтому я обеспокоен тем, что мой код может вызвать проблемы в будущем. Мне пришлось вручную установить свойства навигации на «EntityState.Modified». Моя модель может в конечном итоге иметь много уровней навигационных объектов и коллекций. Есть ли более простой способ обновить связанные объекты? Если нет более простого способа, хорошо ли этот подход?

Вот вид модели

public class ViewModel {
public ViewModel() { }
public ViewModel(Context context) {
this.Options = new SelectList(context.Options, "Id", "Name");
}
public Parent Parent { get; set; }
public SelectList Options { get; set; }
}

классы сущностей

public class Parent {
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    public virtual ChildOne ChildOne { get; set; }
    public virtual ChildTwo ChildTwo { get; set; }
}
public class ChildOne {
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    public virtual Parent Parent { get; set; }
    public virtual int OptionId { get; set; }
    public virtual Option Option { get; set; }
}
public class ChildTwo {
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    public virtual Parent Parent { get; set; }
    public virtual int OptionId { get; set; }
    public virtual Option Option { get; set; }
}
public class Option {
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual ICollection<ChildOne> ChildrenOnes { get; set; }
    public virtual ICollection<ChildTwo> ChildrenTwos { get; set; }
}

контекст

public class Context : DbContext {
    public DbSet<Parent> Parents { get; set; }
    public DbSet<ChildOne> ChildrenOnes { get; set; }
    public DbSet<ChildTwo> ChildrenTwos { get; set; }
    public DbSet<Option> Options { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder) {
        base.OnModelCreating(modelBuilder);
        modelBuilder.Entity<Parent>()
            .HasOptional(x => x.ChildOne)
            .WithOptionalPrincipal(x => x.Parent);
        modelBuilder.Entity<Parent>()
            .HasOptional(x => x.ChildTwo)
            .WithOptionalPrincipal(x => x.Parent);
    }
}

Контроллер

private Context db = new Context();

public ActionResult Edit() {
    ViewModel viewmodel = new ViewModel(db);
    viewmodel.Parent = db.Parents.Find(1);
    return View(viewmodel);
}

public void Save(Parent parent) {
    if (ModelState.IsValid) {
        db.Entry(parent).State = EntityState.Modified;
        db.Entry(parent.ChildOne).State = EntityState.Modified;
        db.Entry(parent.ChildTwo).State = EntityState.Modified;
        db.SaveChanges();
    }
}

и просмотр

@model MvcApp7.Models.ViewModel

<div id="Parent">
    @Html.HiddenFor(model => model.Parent.Id)
    @Html.TextBoxFor(model => model.Parent.Name)
    <div id="ChildOne">
        @Html.HiddenFor(model => model.Parent.ChildOne.Id)
        @Html.TextBoxFor(model => model.Parent.ChildOne.Name)
        @Html.DropDownListFor(model => model.Parent.ChildOne.OptionId, Model.Options)
    </div>
    <div id="ChildTwo">
        @Html.HiddenFor(model => model.Parent.ChildTwo.Id)
        @Html.TextBoxFor(model => model.Parent.ChildTwo.Name)
        @Html.DropDownListFor(model => model.Parent.ChildTwo.OptionId, Model.Options)
    </div>
</div>

<input id="SaveButton" type="button" value="save" />
<script type="text/javascript">
    $('#SaveButton').click(function () {
        var data = $('input, select, textarea').serialize();
        $.post('@Url.Action("Save")', data, function () { });
    });
</script>

1 Ответ

3 голосов
/ 19 июля 2011

Да, вы делаете все правильно.При работе с отдельными сущностями, такими как в веб-приложении, вы должны точно сказать EF, в каком состоянии находится каждая сущность.В вашем сценарии вы сначала вызовете:

db.Entry(parent).State = EntityState.Modified;

В EFv4.1 эта операция вызывает присоединение parent к контексту.Только присоединенные сущности могут быть сохранены в базе данных при вызове SaveChanges.Состояние объекта установлено как измененное, поэтому контекст будет пытаться обновить существующую запись в базе данных при сохранении объекта.Когда вы вызывали это утверждение, произошла еще одна важная вещь: все связанные сущности также прикреплены, но их состояние установлено на неизменное.Вы должны вручную установить правильное состояние всех связанных сущностей, потому что EF не знает, какая из них новая, измененная или удаленная.Вот почему ваши следующие вызовы также являются правильными.

Редактировать:

Имейте в виду, что это обновляет значения в родительском и дочернем элементах, но не обновляет само отношение.Если вы поменяете местами одного ребенка с другим, процесс будет намного сложнее при использовании независимых ассоциаций .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...