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.