Entity Framework Code First Repository 真的很通用并且有两个上下文的问题

Posted

技术标签:

【中文标题】Entity Framework Code First Repository 真的很通用并且有两个上下文的问题【英文标题】:Entity Framework Code First Repository really generic and problems with two context 【发布时间】:2011-05-31 14:13:32 【问题描述】:

对不起,我的英语不好。 在我工作的公司中,我们正在迁移到 Entity Framework Code First。 但是当我创建两个存储库实例时会出现问题

RepositoryGeneric<Anuncio> repAnuncio1 = new RepositoryGeneric<Anuncio>();
Anuncio anuncio1 = repAnuncio1.find(1)

Anuncio anuncio2 = new Anuncio (1,20,"any thing");

RepositoryGeneric<Anuncio> repAnuncio2 = new RepositoryGeneric<Anuncio>();

repAnuncio2.salvar(anuncio2); //ok work

repAnuncio2.salvar(anuncio1); // error the anuncio1 is atach in repAnuncio1

这只是一个例子,但在实际应用中我需要多个存储库交互。

否则,我们的应用程序使用 DataContext:

  public static void Save(Entity entity)
  
    if (entity != null)
    
      SqlServer sql = new SqlServer();

      Type tipoEntidade = entity.GetType();

      PropertyInfo[] propriedades = tipoEntidade.GetProperties();

      foreach (PropertyInfo propriedade in propriedades)
      
        if (propriedade.PropertyType.IsPublic && propriedade.CanWrite && propriedade.PropertyType.Namespace == "System")
        
          object valor = propriedade.GetValue(entidade, null);

          if (valor != null && propriedade.Name != "ID" && propriedade.Name != "Excluido")
            sql.AdicionarParametro("@" + propriedade.Name, valor);
        
      

但在实体框架中我无法实现。

其他:

public int Save(Anuncio anuncio)
  
   if (anuncio.Id != 0)
    // ctx.Anuncio.Attach(anuncio);
//attach Error  when othe repository get
//else i need...

BancoContext ctx = new BancoContext (); //my Dbcontext
AnuncioAxiliar = ctx.Anuncio.FirstOrDefault(x => x.Id == entidade.Id); //Entity help

AnuncioAxiliar.Nome = anuncio.Nome;
AnuncioAxiliar.Cliente= anuncio.Cliente;
AnuncioAxiliar.Contrato= anuncio.Contrato;

ctx.SaveChanges(); //vai salvar o AnuncioAxiliar 



   else
    ctx.Set(entidade.GetType()).Add(entidade);

   return ctx.SaveChanges();
  

但是我需要为每个类 Poco 提供一个 Save 方法

有什么想法吗?

【问题讨论】:

【参考方案1】:

这是常见的问题。您不能将从一个上下文加载的实体传递到另一个上下文。在一个工作单元(逻辑事务)中工作时,您应该在存储库之间共享上下文。在工作单元中,每种类型使用一个存储库实例也足够了。

如果你想将实体从一个上下文传递到另一个上下文,你必须首先通过调用将它从第一个上下文中分离出来:

ctx.Entry(entity).State = EntityState.Detached;

请注意,如果实体有任何已加载的关系,当您将其从上下文中分离出来时,这些关系将会丢失/破坏。

【讨论】:

但大多数情况下,另一个类中的一个方法将接收实体保存与否并返回第一个方法,使我无法分离 所以为逻辑事务使用一个上下文。这就是重点。在这种情况下使用多个上下文是完全错误的用法。【参考方案2】:

您需要在存储库之间共享 EF db 上下文。当您通过 EF 从数据库中检索数据时,EF 返回的对象将附加到 db 上下文的特定实例以进行更改跟踪。如果您尝试在另一个数据库上下文中对该实体执行任何操作,EF 将抛出异常,因为数据库上下文可以看到它已经附加到另一个上下文。

请注意,如果这是一个 Web 应用程序,您的 db 上下文应该只在存储库之间共享仅在同一个 Web 请求中。如果它们在所有 Web 请求的所有存储库之间共享,则会发生冲突。

【讨论】:

【参考方案3】:

更改 RepositoryGeneric 的构造函数以接受您的数据上下文作为参数。然后对所有存储库使用相同的上下文。您可能应该使用依赖注入来实现这一点。

类似下面的东西

    public class RepositoryGeneric<TEntity>
    
        public RepositoryGeneric(DomainContext domainContext)
        
            DomainContext = domainContext;         
        

        protected DomainContext DomainContext  get; private set; 

        protected virtual IDbSet<TEntity> DbSet
        
            get  return DomainContext.Set<TEntity>(); 
        

        public virtual TEntity GetByKey(params object[] keys)
        
            return DbSet.Find(keys);
        
   

【讨论】:

以上是关于Entity Framework Code First Repository 真的很通用并且有两个上下文的问题的主要内容,如果未能解决你的问题,请参考以下文章

Entity Framework 5.0 Code First全面学习

Entity Framework Code First

ADO.NET Entity Framework -Code Fisrt 开篇

转:Entity Framework 5.0 Code First全面学习

Entity Framework Code First 不允许Entity直接实现接口

Entity Framework Code First 迁移 Migrations