Контроллер сохраняет экземпляры, на которые ссылаются, как новые экземпляры вместо обновления существующих.

Я искал и нашел следующие ссылки ссылка и ссылка b, которая не объясняла что я делаю неправильно.

Я использую MVC3 + Fluent + NHibernate с Fluent в режиме автоматического сопоставления со следующей конфигурацией:

NHibernate.Cfg.Configuration().Configure();
XXConfiguration autoMappingConf = new XXConfiguration();
FluentConfiguration fc = Fluently.Configure()
     .Database(MsSqlConfiguration.MsSql2008.ConnectionString(
         ConfigurationManager.ConnectionStrings[myConnString].ConnectionString
      )
      .ShowSql());
fc.ExposeConfiguration(cfg =>      cfg.SetProperty(NHibernate.Cfg.Environment.CurrentSessionContextClass, "web"));
fc.Mappings(m => m.AutoMappings.Add(AutoMap.AssemblyOf<BasicEntity>(autoMappingConf)
                .UseOverridesFromAssemblyOf<AccountMappingOverride>()
                .Conventions.Add(DefaultCascade.All()))
                );
        return fc.BuildSessionFactory();
    }

и со следующим переопределением:

public class AccountMappingOverride: IAutoMappingOverride<Account>
{
    public void Override(AutoMapping<Account> mapping)
    {
        mapping.HasMany(a => a.ChildrenAccounts).KeyColumn("ParentAccount_id");
    }
}

У меня есть следующие модели:

public abstract class Entity<TId>
{
    public virtual TId Id { get; set; }
    public virtual int ExternalId { get; set; }
}

public abstract class BasicEntity : Entity<int>{}

public abstract class MainEntity : BasicEntity
{
    public virtual int Version { get; set; }
    public virtual bool Active { get; set; }
}

public class Language : MainEntity 
{
    public virtual string Code { get; set; }
    public virtual string Name { get; set; }
}

public class Account : MainEntity
{
    public virtual string Name { get; set; }
    public virtual Language Language { get; set; }
    public virtual Account ParentAccount { get; set; }
    public virtual IList<Account> ChildrenAccounts { get; set; }
    public virtual IList<User> Users { get; set; }

}

 public class User : MainEntity
{
    public virtual string Name { get; set; }
    public virtual string Surname { get; set; }
    public virtual string Email { get; set; }
    [DataType(DataType.Password)]
    public virtual string Password { get; private set; }
    public virtual Language Language { get; set; }
    public virtual Account Account { get; set; }
    public virtual DateTime? LastLoginDate { get; set; }
    public virtual DateTime? LastPasswordChangeDate { get; set; }
}

И представление, в котором отображаются поля для создания новой учетной записи:

@model XX.Models.Account

@{
   ViewBag.Title = "New Account";
   Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>New account</h2>

@using (Html.BeginForm())
{
    @Html.ValidationSummary(true)

    <div class="editor-label">
        @Html.LabelFor(model => model.Name)
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.Name)
        @Html.ValidationMessageFor(model => model.Name)
    </div>


    <div class="editor-label">
        @Html.LabelFor(model => model.ParentAccount)
    </div>
    <div class="editor-field">
        @Html.DropDownListFor(model => model.ParentAccount.Id, XX.Utils.SelectList<XX.Models.Account>("Name", (string)ViewBag.parentAccountId))
        @Html.ValidationMessageFor(model => model.ParentAccount)
    </div>

    <div class="editor-label">
        @Html.LabelFor(model => model.Language)
    </div>
    <div class="editor-field">
        @Html.DropDownListFor(model => model.Language.Id,  XX.Utils.SelectList<XX.Models.Language>("Name", ""))
        @Html.ValidationMessageFor(model => model.Language)
    </div>

    <p>
        <input type="submit" value="Add" />
    </p>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

Контроллер сохраняет, но вместо простого назначения поля «Язык» в процессе сохранения создается новый язык вместо обновления существующего. Проверяя объект Account, переданный контроллеру, мы заметили, что он содержит ссылку на объект Language с уже существующим идентификатором. Это делается для любого сопоставления ссылок.

 [HttpPost]
 [NeedsPersistence]
 public ActionResult Create(Account account)
    {
        if (ModelState.IsValid)
        {
            accountDao.Save(account, currentUser);
            return RedirectToAction("Tree");
        }
        else {
            return View();
        }
    }

Как я могу заставить сохранение распознавать, что язык уже существует?


person user616397    schedule 14.02.2011    source источник


Ответы (2)


Смотрите эту строку:

@Html.DropDownListFor(модель => model.Language.Id, XX.Utils.SelectList("Имя", ""))

вы говорите, что такое поле отображения, но поле данных представляет собой пустую строку.

Я предполагаю, что это будет выглядеть так:

@Html.DropDownListFor(модель => model.Language.Id, XX.Utils.SelectList("Имя", "Идентификатор"))

person JuanMa    schedule 25.02.2011

мы решили проблему, определив ViewModels (свойство Language мы исключили, потому что оно было удалено из модели, но тот же случай применим к ParentAccount) и контроллер следующим образом:

public class AccountEdit
{
    public int Id { get; set; }
    [Required]
    [LocalizedDisplayName("Name")]
    public string Name { get; set; }
    [LocalizedDisplayName("ParentAccount")]
    public int ParentAccount { get; set; }
    [LocalizedDisplayName("Role")]
    public Role Role { get; set; }

    public AccountEdit() { }

    public AccountEdit(Account a)
    {
        Id = a.Id;
        Name = a.Name;
        ParentAccount = a.ParentAccount!=null ? a.ParentAccount.Id : 0;
        Role = a.Role;
    }

    public Account BoundAccount()
    {
        DataAccessObject<Account> dao = new DataAccessObject<Account>();
        Account account = dao.Get(Id);
        account.Name = Name;
        if (ParentAccount == default(int))
            account.ParentAccount = null;
        else
            account.ParentAccount = dao.Get(ParentAccount);
        return account;
    }
}

    [HttpPost]
    [NeedsPersistence]
    public ActionResult CreateDistributor(DistributorCreate dc)
    {
        if (ModelState.IsValid)
        {
            Account account = dc.BoundAccount();
            accountDao.Save(account, currentUser);
            return RedirectToAction("Index");
        }
        else {
            return View(dc);
        }
    }
person user616397    schedule 01.03.2011