【发布时间】:2018-08-03 15:35:12
【问题描述】:
在我的自定义开发应用程序中,我收到一个错误“一个实体对象不能被多个 IEntityChangeTracker 实例引用”。据我了解,这意味着我不能使用附加到多个上下文的同一实体。为了重现错误,我使用以下代码创建了一个沙盒应用程序:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.ModelConfiguration;
using System.Linq;
using System.Linq.Expressions;
namespace EntityFrameworkRepositoryPatternTestApp
{
public class Item
{
public Guid Id { get; set; }
public string SomeString { get; set; }
public int SomeInt { get; set; }
public double SomeDouble { get; set; }
}
public class Context : DbContext
{
public DbSet<Item> Items { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new ItemConfiguration());
base.OnModelCreating(modelBuilder);
}
public Context() : base("Connection")
{
}
}
public class ItemConfiguration : EntityTypeConfiguration<Item>
{
public ItemConfiguration()
{
this.ToTable("Items").HasKey(i => i.Id);
this.Property(i => i.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
this.Property(i => i.SomeString).HasMaxLength(255);
this.Property(i => i.SomeInt);
this.Property(i => i.SomeDouble);
}
}
public interface IRepository<T>
{
T Add(T item);
IEnumerable<T> Get(Expression<Func<T, bool>> filter = null);
T GetById(Guid id);
void Remove(T item);
}
public class EntityFrameworkRepository<TEntity> : IRepository<TEntity> where TEntity : class
{
private readonly IDbSet<TEntity> dbSet;
private Context Context { get; }
public TEntity Add(TEntity item)
{
this.dbSet.Add(item);
return item;
}
public IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> filter = null)
{
IQueryable<TEntity> query = this.dbSet;
if (filter != null)
query = query.Where(filter);
return query.ToList();
}
public TEntity GetById(Guid id)
{
return this.dbSet.Find(id);
}
public void Remove(TEntity item)
{
this.dbSet.Remove(item);
}
public EntityFrameworkRepository(Context context)
{
this.Context = context;
this.dbSet = this.Context.Set<TEntity>();
}
}
public interface IDomainContext
{
int SaveChanges();
int SaveChangesWithoutClientValidation();
}
public interface IDomainContext<TEntity> : IDomainContext where TEntity : class
{
IRepository<TEntity> Entities { get; }
void Update(TEntity item);
void Attach(TEntity item);
void Detach(TEntity item);
}
public class DomainContext<TEntity> : IDomainContext<TEntity>, IDisposable where TEntity : class
{
private Context context;
public int SaveChanges()
{
return this.context.SaveChanges();
}
public IRepository<TEntity> Entities => this.GetRepository<TEntity>();
public void Update(TEntity item)
{
var entry = this.context.Entry(item);
foreach (var propertyName in entry.OriginalValues.PropertyNames)
{
var original = entry.OriginalValues.GetValue<object>(propertyName);
var current = entry.CurrentValues.GetValue<object>(propertyName);
if ((original == null && current != null) ||
((original != null) && !original.Equals(current)))
entry.Property(propertyName).IsModified = true;
}
}
public void Attach(TEntity item) =>
this.context.Set<TEntity>().Attach(item);
public void Detach(TEntity entity) =>
((IObjectContextAdapter)this.context).ObjectContext.Detach(entity);
public void Dispose()
{
this.context.Dispose();
}
private IRepository<T> GetRepository<T>() where T : class
{
var resultRepository = new EntityFrameworkRepository<T>(this.context);
return resultRepository;
}
public DomainContext()
{
this.context = new Context();
}
}
public class Program
{
static void Main(string[] args)
{
var domainContext = new DomainContext<Item>();
{
var item = new Item() { Id = Guid.NewGuid(), SomeDouble = 666, SomeInt = 777, SomeString = "some string"};
domainContext.Entities.Add(item);
domainContext.SaveChanges();
using (var domainContext2 = new DomainContext<Item>())
{
if (item != null)
{
domainContext2.Attach(item);
item.SomeDouble = 11.28;
domainContext2.Update(item);
domainContext2.SaveChanges();
}
}
}
domainContext.Dispose();
}
}
}
问题是我在这个沙盒应用程序中实际上并没有收到错误。所以现在我需要了解,Entity Framework 是否真的禁止将单个实体附加到多个上下文以及如何克服这个限制。我想到的解决方案是在将实体副本附加到另一个上下文时创建它。但现在我认为,真的可以在不创建副本的情况下将实体附加到另一个上下文。
【问题讨论】:
-
我认为您缺少的关键是实体只能由一个上下文在给定时间跟踪。您可以将实体的状态设置为
EntityState.Detached以停止对其进行跟踪,然后将其附加到另一个上下文 -
好的。但是为什么我在测试应用程序中没有出错?它显然在两个上下文之间共享一个实体。
标签: .net entity-framework