同じトピックに関する多くの質問を見てきましたが、まだ解決策が見つかりません. 問題を引き起こしているコードは次のとおりです。
public async Task<IHttpActionResult> Post(FullOrderViewModel fullOrder)
{
//Get all order items
List<OrderItem> orderItems = new List<OrderItem>();
foreach (var oi in fullOrder.Order)
{
var color = _colorRepo.Find(oi.ColorId);
var item = new OrderItem
{
Quantity = oi.Quantity,
Color = color
};
orderItems.Add(item);
}
//Get customer id
var customer = await _adminRepo.GetCustomerByUserName(fullOrder.Customer.UserName);
var billAddress = _addressRepo.All.FirstOrDefault(x => x.AddressLine == fullOrder.BillingAddress.AddressLine && x.PostalCode == fullOrder.BillingAddress.PostalCode);
var deliveryAddress = _addressRepo.All.FirstOrDefault(x => x.AddressLine == fullOrder.DeliveryAddress.AddressLine && x.PostalCode == fullOrder.DeliveryAddress.PostalCode);
//CASE : sample order
if (fullOrder.OrderType == OrderType.Sample)
{
var order = new SampleOrder {
Type = OrderType.Sample,
Status = "Unauthorized",
Origin = Origin.Online,
OrderItems = orderItems,
CreationDate = DateTime.Now,
CustomerId = customer.Id,
BillAddressId = billAddress.AddressId,
DeliveryAddressId = deliveryAddress.AddressId
};
try
{
_sampleOrderRepo.InserGraph(order);
_unitOfWork.Save();
}
catch (Exception e)
{
return InternalServerError(e);
}
リポジトリを取得する方法は、OrderController コンストラクターでの依存性注入によるもので、標準的な方法だと思います。私のレポはそれぞれ、次のように構築されています。
public class SampleOrderRepository : EntityRepository<SampleOrder, IPhoeniceUnitOfWork<PhoeniceContext>>, ISampleOrderRepository
{
public SampleOrderRepository(IPhoeniceUnitOfWork<PhoeniceContext> unitOfWork) : base(unitOfWork)
{
}
protected override IDbSet<SampleOrder> List(IPhoeniceUnitOfWork<PhoeniceContext> unitOfWork)
{
return unitOfWork.Context.SampleOrders;
}
protected override Expression<Func<SampleOrder, bool>> FindInt(int id)
{
return x => x.OrderId == id;
}
}
一般的なエンティティ リポジトリのメソッドをオーバーライドする場所:
public abstract class EntityRepository<T, TContext> : IEntityRepository<T>
where T : class, IObjectWithState
where TContext : IUnitOfWork<EntityContext>
{
protected readonly TContext _unitOfWork;
protected EntityRepository(TContext unitOfWork)
{
_unitOfWork = unitOfWork;
}
protected virtual IDbSet<T> List(TContext unitOfWork)
{
throw new NotImplementedException("List operation not implemented!");
}
protected virtual Expression<Func<T, bool>> FindInt(int id)
{
throw new NotImplementedException("Finding entity with an int is not implemented!");
}
protected virtual Expression<Func<T, bool>> FindString(string id)
{
throw new NotImplementedException("Finding entity with an int is not implemented!");
}
public virtual IQueryable<T> All { get { return List(_unitOfWork); } }
public virtual IQueryable<T> AllIncluding(params Expression<Func<T, object>>[] includeProperties)
{
return includeProperties.Aggregate(All, (current, includeProperty) => current.Include(includeProperty));
}
public virtual T Find(int id)
{
return All.FirstOrDefault(FindInt(id));
}
public virtual T FindByString(string id)
{
return All.FirstOrDefault(FindString(id));
}
public virtual void InserGraph(T entity)
{
List(_unitOfWork).Add(entity);
}
public void InsertOrUpdate(T entity)
{
if (entity.ObjectState == State.Added) // New entity
{
_unitOfWork.Context.Entry(entity).State = EntityState.Added;
}
else // Existing entity
{
_unitOfWork.Context.Entry(entity).State = EntityState.Modified;
_unitOfWork.Context.ApplyStateChanges();
}
}
public virtual void Delete(int id)
{
var entity = Find(id);
List(_unitOfWork).Remove(entity);
}
public void Dispose()
{
}
}
最後に、これは私の UnitOfWork アイテムです:
public class PhoeniceUnitOfWork : IPhoeniceUnitOfWork<PhoeniceContext>
{
private readonly PhoeniceContext _context;
public PhoeniceUnitOfWork() : base()
{
_context = new PhoeniceContext();
}
//Left for testing purposes
public PhoeniceUnitOfWork(PhoeniceContext context)
{
_context = context;
}
public int Save()
{
return _context.SaveChanges();
}
public void Dispose()
{
_context.Dispose();
}
public IAddressRepository AddressRepository
{
get { return new AddressRepository(this); }
}
public IColorRepository ColorRepository
{
get { return new ColorRepository(this); }
}
public IHideOrderRepository HideOrderReposiotory
{
get { return new HideOrderRepository(this); }
}
public ISampleOrderRepository SampleOrderRepository
{
get { return new SampleOrderRepository(this); }
}
public ITaxonomyRepository TaxonomyRepository
{
get { return new TaxonomyRepository(this); }
}
PhoeniceContext IUnitOfWork<PhoeniceContext>.Context
{
get { return _context; }
}
}
私が使用しているコンテキスト
public class PhoeniceContext : EntityContext
{
// You can add custom code to this file. Changes will not be overwritten.
//
// If you want Entity Framework to drop and regenerate your database
// automatically whenever you change your model schema, add the following
// code to the Application_Start method in your Global.asax file.
// Note: this will destroy and re-create your database with every model change.
//
// System.Data.Entity.Database.SetInitializer(new System.Data.Entity.DropCreateDatabaseIfModelChanges<Phoenice.EntityFramework.Models.PhoeniceContext>());
public PhoeniceContext()
: base("Phoenice")
{
Database.SetInitializer<PhoeniceContext>(new DropCreateIfChangeInitializer());
//Database.SetInitializer<PhoeniceContext>(new DropCreateDatabaseAlways());
}
public DbSet<Address> Addresses { get; set; }
public DbSet<SampleOrder> SampleOrders { get; set; }
public DbSet<HideOrder> HideOrders { get; set; }
public DbSet<OrderItem> OrderItems { get; set; }
public DbSet<Color> Colors { get; set; }
public DbSet<Taxonomy> Taxonomies { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//There is OnModelCreating already overwritten in IdentityDbContext
//with all details required for ASP.NET identity
base.OnModelCreating(modelBuilder);
//solution for this mapping: http://stackoverflow.com/questions/11632951/primary-key-violation-inheritance-using-ef-code-first
modelBuilder.Entity<SampleOrder>()
.HasKey(x => x.OrderId)
.Map(m =>
{
//Requires EF 6.1
m.MapInheritedProperties();
m.ToTable("SampleOrders");
})
.Property(x => x.OrderId)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
modelBuilder.Entity<HideOrder>().Map(m =>
{
//Requires EF 6.1
m.MapInheritedProperties();
m.ToTable("HideOrders");
});
modelBuilder.Entity<HideOrder>().HasKey(x => x.OrderId);
}
}
私が示しているのは大量のコードであることはわかっていますが、これらがすべてデータ アクセス レイヤーのビルディング ブロックであることを願っています。何らかの理由で、SampleOrders で InsertGraph メソッドを呼び出すと、「IEntityChangeTracker の複数のインスタンスでエンティティ オブジェクトを参照できません」という例外が発生します。このコードを何十回も調べましたが、なぜこのエラー メッセージがスローされるのかわかりません