この単純なモデルとビューモデルのシナリオを考えてみましょう:
public class SomeModel
{
public virtual Company company {get; set;}
public string name {get; set;}
public string address {get; set;}
//some other few tens of properties
}
public class SomeViewModel
{
public Company company {get; set;}
public string name {get; set;}
public string address {get; set;}
//some other few tens of properties
}
発生する問題は次のとおりです。
会社が不要な編集ページがあるため、データベースから取得しません。フォームが送信されたら、次のことを行います。
SomeModel destinationModel = someContext.SomeModel.Include("Company").Where( i => i.Id == id) // assume id is available from somewhere.
それから私は
Company oldCompany = destinationModel.company; // save it before mapper assigns it null
Mapper.Map(sourceViewModel,destinationModel);
//After this piece of line my company in destinationModel will be null because sourceViewModel's company is null. Great!!
//so I assign old company to it
destinationModel.company = oldCompany;
context.Entry(destinationModel).State = EntityState.Modified;
context.SaveChanges();
そして問題は、oldCompany を会社に割り当てても、savechanges 後にデータベースでまだ null です。
ノート:
これらの行を変更すると:
destinationModel.company = oldCompany;
context.Entry(destinationModel).State = EntityState.Modified;
context.SaveChanges();
これらに:
context.Entry(destinationModel).State = EntityState.Modified;
destinationModel.company = oldCompany;
context.Entry(destinationModel).State = EntityState.Modified;
context.SaveChanges();
状態を 2 回変更したことに注意してください。正常に動作します。何が問題になる可能性がありますか? これは ef 4.1 のバグですか?
これは、この問題に対処するサンプル コンソール アプリケーションです。
using System;
using System.Linq;
using System.Data.Entity;
using System.ComponentModel.DataAnnotations;
using AutoMapper;
namespace Slauma
{
public class SlaumaContext : DbContext
{
public DbSet<Company> Companies { get; set; }
public DbSet<MyModel> MyModels { get; set; }
public SlaumaContext()
{
this.Configuration.AutoDetectChangesEnabled = true;
this.Configuration.LazyLoadingEnabled = true;
}
}
public class MyModel
{
public int Id { get; set; }
public string Foo { get; set; }
[ForeignKey("CompanyId")]
public virtual Company Company { get; set; }
public int? CompanyId { get; set; }
}
public class Company
{
public int Id { get; set; }
public string Name { get; set; }
}
public class MyViewModel
{
public string Foo { get; set; }
public Company Company { get; set; }
public int? CompanyId { get; set; }
}
class Program
{
static void Main(string[] args)
{
Database.SetInitializer<SlaumaContext>(new DropCreateDatabaseIfModelChanges<SlaumaContext>());
SlaumaContext slaumaContext = new SlaumaContext();
Company company = new Company { Name = "Microsoft" };
MyModel myModel = new MyModel { Company = company, Foo = "Foo"};
slaumaContext.Companies.Add(company);
slaumaContext.MyModels.Add(myModel);
slaumaContext.SaveChanges();
Mapper.CreateMap<MyModel, MyViewModel>();
Mapper.CreateMap<MyViewModel, MyModel>();
//fetch the company
MyModel dest = slaumaContext.MyModels.Include("Company").Where( c => c.Id == 1).First(); //hardcoded for demo
Company oldCompany = dest.Company;
//creating a viewmodel
MyViewModel source = new MyViewModel();
source.Company = null;
source.CompanyId = null;
source.Foo = "foo hoo";
Mapper.Map(source, dest); // company null in dest
//uncomment this line then only it will work else it won't is this bug?
//slaumaContext.Entry(dest).State = System.Data.EntityState.Modified;
dest.Company = oldCompany;
slaumaContext.Entry(dest).State = System.Data.EntityState.Modified;
slaumaContext.SaveChanges();
Console.ReadKey();
}
}
}