repositorio patrón patrones patron parte net implementación generico framework diseño capa abstracto c# asp.net generics entity-framework-6 self-reference

patrón - patrones de diseño repositorio c#



El objeto de entidad no puede ser referenciado por varias instancias de IEntityChangeTracker en un repositorio genérico (2)

Creé un UnitOfWork a partir de este ejemplo ...

public class UnitOfWork : IDisposable { private DbContext context = new DbContext(); private FooRepository fooRepository; public FooRepository fooRepository { get { if (this.fooRepository == null) { this.fooRepository = new FooRepository(context); } return fooRepository; } } public void Save() { context.SaveChanges(); } private bool disposed = false; protected virtual void Dispose(bool disposing) { if (!this.disposed) { if (disposing) { context.Dispose(); } } this.disposed = true; } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } }

luego cambié cada repositorio para aceptar un contexto ...

public class FooRepository : GenericRepository<Foo>, IFooRepository { public FooRepository(DbContext context) : base(context) {} }

He utilizado una interfaz genérica y un repositorio en este tugberkugurlu , que es ...

public interface IGenericRepository<T> where T : class { IQueryable<T> GetAll(); IQueryable<T> FindBy(Expression<Func<T, bool>> predicate); void Add(T entity); void Delete(T entity); void Edit(T entity); void Save(); }

y este repositorio genérico

public abstract class GenericRepository<C, T> : IGenericRepository<T> where T : class where C : DbContext, new() { private C _entities = new C(); public C Context { get { return _entities; } set { _entities = value; } } public virtual IQueryable<T> GetAll() { IQueryable<T> query = _entities.Set<T>(); return query; } public IQueryable<T> FindBy(System.Linq.Expressions.Expression<Func<T, bool>> predicate) { IQueryable<T> query = _entities.Set<T>().Where(predicate); return query; } public virtual void Add(T entity) { _entities.Set<T>().Add(entity); } public virtual void Delete(T entity) { _entities.Set<T>().Remove(entity); } public virtual void Edit(T entity) { _entities.Entry(entity).State = System.Data.EntityState.Modified; } public virtual void Save() { _entities.SaveChanges(); } }

que ahora se puede usar así ...

public class FooRepository : GenericRepository<FooBarEntities, Foo>, IFooRepository { public Foo GetSingle(int fooId) { var query = GetAll().FirstOrDefault(x => x.FooId == fooId); return query; } }

ahora, todo está, o estaba bien hasta que tuve una entidad autorreferencial, como esta ...

public class Question { [Key] public string QuestionID { get; set; } public string QuestionNumber { get; set; } public string Message { get; set; } public DateTime? DatePosted { get; set; } public DateTime? Modified { get; set; } public bool HasSubgroups { get; set; } public string ApplicationUserId { get; set; } [ForeignKey("ApplicationUserId")] public virtual ApplicationUser ApplicationUser { get; set; } public string PaperID { get; set; } [ForeignKey("PaperID")] public virtual PaperEntity Paper { get; set; } public ICollection<QuestionTag> Tags { get; set; } public ICollection<QuestionVote> Votes { get; set; } public virtual ICollection<Answer> Answers { get; set; } public virtual ICollection<QuestionComment> QuestionComments { get; set; } public string ParentQuestionID { get; set; } [ForeignKey("ParentQuestionID")] public virtual Question QuestionReference { get; set; } public virtual ICollection<Question> Questions { get; set; } }

y como puede ver, mi modelo me permite hacer preguntas secundarias a una pregunta. y así es como trato de implementarlo ...

dynamic model = modela; string q_id = model.QuestionID.ToString(); var question = q_id.IsNullOrEmpty() ? null : await questionRepository.FindBy(id => id.QuestionID == q_id); if (question == null) { question = new Question { QuestionID = Guid.NewGuid().ToString("D"), QuestionNumber = model.ParentQuestionNumber, PaperID = model.PaperID, Message = model.QuestionTitle, ApplicationUserId = userid, DatePosted = DateTime.UtcNow, Tags = new List<QuestionTag>() }; await questionRepository.Add(question); } var questionQuestion = new Question { QuestionID = Guid.NewGuid().ToString("D"), ParentQuestionID = question.QuestionID, QuestionNumber = model.QuestionNumber, PaperID = question.PaperID, Message = model.Message, ApplicationUserId = userid, DatePosted = DateTime.UtcNow, Tags = new List<QuestionTag>() }; question.Questions = new List<Question>{questionQuestion}; await questionRepository.Update(question); await questionRepository.Save();

y después de que puedo guardar la primera subpregunta, la segunda pregunta arroja un error en ...

_ctx.Entry(entity).State = EntityState.Modified;

diciendo...

A first chance exception of type ''System.InvalidOperationException'' occurred in EntityFramework.dll Additional information: An entity object cannot be referenced by multiple instances of IEntityChangeTracker.

Incluso he intentado usar IDisposable en GenericRepository sin suerte ... Cualquier ayuda oliendo a sugerencia será muy apreciada ...


Supongo que tienes problemas debido a los contextos. Probablemente tienes dos contextos con la misma entidad. Puede ser debido a la creación de context-per-repository . Intente utilizar el patrón UnitOfWork o simplemente cree un contexto para todos los repositorios.