开发者

Controller saves referenced instances as new instances instead of updating the existing ones

I searched and found the following links link a and link b which did not explain what I am doing wrong.

I am using MVC3 + Fluent + NHibernate with Fluent in automapper mode with the following configuration:

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();
    }

and with the following override:

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

I have the following models:

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; }
}

And a view which displays the fields to create a new Account:

@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" />
开发者_JAVA技巧    </p>
}

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

The Controller saves, but instead of simply assigning the field Language, during the save process a new Language gets created instead of updating the existing one. Checking the Account object passed to the controller we noticed it has a reference to a Language object with an already existing id. This is done for any reference mapping.

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

How can I get the save to recognize the Language is already existing?


See this line:

@Html.DropDownListFor(model => model.Language.Id, XX.Utils.SelectList("Name", ""))

you're telling what the display field is but the data field is an empty string.

I guess it would go like this:

@Html.DropDownListFor(model => model.Language.Id, XX.Utils.SelectList("Name", "Id"))


we solved the issue by defining ViewModels (we left the Language property out because it was dropped from the model, but the same case applies to ParentAccount) and the controller as follows:

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);
        }
    }
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜