Patrón de depósito con Entity Framework 4.1 y relaciones padre / hijo

Todavía tengo cierta confusión con el patrón de repositorio. La razón principal por la que quiero usar este patrón es para evitar llamar a operaciones de acceso a datos específicas de EF 4.1 desde el dominio. Prefiero llamar operaciones CRUD genéricas desde una interfaz IRepository. Esto facilitará las pruebas y si alguna vez tengo que cambiar el marco de acceso a datos en el futuro, podré hacerlo sin refactorizar mucho código.

Aquí hay un ejemplo de mi situación:

Tengo 3 tablas en la base de datos:Group, Person yGroupPersonMap. GroupPersonMap es una tabla de enlaces y solo consiste enGroup yPerson claves principales. Creé un modelo EF de las 3 tablas con el diseñador VS 2010. EF fue lo suficientemente inteligente como para asumirGroupPersonMap es una tabla de enlaces, por lo que no se muestra en el diseñador. Quiero usar mis objetos de dominio existentes en lugar de las clases generadas por EF, así que apago la generación de código para el modelo.

Mis clases existentes que coinciden con el modelo EF son las siguientes:

public class Group
{
   public int GroupId { get; set; }
   public string Name { get; set; }

   public virtual ICollection<Person> People { get; set; }
}

public class Person
{
   public int PersonId {get; set; }
   public string FirstName { get; set; }

   public virtual ICollection<Group> Groups { get; set; }
}

Tengo una interfaz de repositorio genérica como esta:

public interface IRepository<T> where T: class
{
    IQueryable<T> GetAll();
    T Add(T entity);
    T Update(T entity);
    void Delete(T entity);
    void Save()
}

y un repositorio EF genérico:

public class EF4Repository<T> : IRepository<T> where T: class
{
    public DbContext Context { get; private set; }
    private DbSet<T> _dbSet;

    public EF4Repository(string connectionString)
    {
        Context = new DbContext(connectionString);
        _dbSet = Context.Set<T>();
    }

    public EF4Repository(DbContext context)
    {
        Context = context;
        _dbSet = Context.Set<T>();
    }

    public IQueryable<T> GetAll()
    {
        // code
    }

    public T Insert(T entity)
    {
        // code
    }

    public T Update(T entity)
    {
        Context.Entry(entity).State = System.Data.EntityState.Modified;
        Context.SaveChanges();
    }

    public void Delete(T entity)
    {
        // code
    }

    public void Save()
    {
        // code
    }
}

Ahora supongamos que solo quiero asignar un @ existenGroup a una @ existenPerson. Tendría que hacer algo como lo siguiente:

        EFRepository<Group> groupRepository = new EFRepository<Group>("name=connString");
        EFRepository<Person> personRepository = new EFRepository<Person>("name=connString");

        var group = groupRepository.GetAll().Where(g => g.GroupId == 5).First();
        var person = personRepository.GetAll().Where(p => p.PersonId == 2).First();

        group.People.Add(person);
        groupRepository.Update(group);

Pero esto no funciona porque EF piensaPerson es nuevo e intentará reINSERT elPerson en la base de datos, lo que provocará un error de restricción de clave principal. Debo usarDbSet 'sAttach método para decirle a EF que elPerson ya existe en la base de datos, así que simplemente cree un mapa entreGroup yPerson en elGroupPersonMap mesa

Entonces para adjuntarPerson al contexto ahora debo agregar unaAttach método para mi IRepository:

public interface IRepository<T> where T: class
{
    // existing methods
    T Attach(T entity);
}

Para corregir el error de restricción de clave principal:

EFRepository<Group> groupRepository = new EFRepository<Group>("name=connString");
EFRepository<Person> personRepository = new EFRepository<Person>(groupRepository.Context);

var group = groupRepository.GetAll().Where(g => g.GroupId == 5).First();
var person = personRepository.GetAll().Where(p => p.PersonId == 2).First();

personRepository.Attach(person);
group.People.Add(person);
groupRepository.Update(group);

Fijo. Ahora tengo que lidiar con otro problema dondeGroup se ACTUALIZA en la base de datos cada vez que creo un mapa de Grupo / Persona. Esto es porque en miEFRepository.Update() método, el estado de la entidad se establece explícitamente enModified'. I must set the Group's state toSin alteraso thea tabla @ Group` no se modifica.

Para solucionar esto, debo agregar algún tipo deUpdate sobrecarga a mi IRepository que no actualiza la entidad raíz, oGroup, en este caso

public interface IRepository<T> where T: class
{
    // existing methods
    T Update(T entity, bool updateRootEntity);
}

La implementación EF4 del método de actualización se vería así:

T Update(T entity, bool updateRootEntity)
{
   if (updateRootEntity)
      Context.Entry(entity).State = System.Data.EntityState.Modified;
   else
      Context.Entry(entity).State = System.Data.EntityState.Unchanged;

    Context.SaveChanges();
}

Mi pregunta es: ¿Me estoy acercando a esto de la manera correcta? Mi repositorio comienza a verse centrado en EF cuando empiezo a trabajar con EF y el patrón del repositorio. Gracias por leer esta larga publicación

Respuestas a la pregunta(1)

Su respuesta a la pregunta