Entity object cannot be referenced by multiple instances of IEntityChangeTracker in a generic repository

asp.net c# entity-framework-6 generics self-reference

Question

i have used a generic interface and repository in this tugberkugurlu, which is...

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();
}

and this generic repository

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();
    }
}

which can now be used like this...

public class FooRepository :
    GenericRepository<FooBarEntities, Foo>, IFooRepository {

    public Foo GetSingle(int fooId) {

        var query = GetAll().FirstOrDefault(x => x.FooId == fooId);
        return query;
    }
}

now, all is, or was well until i had a self referencing entity, like this...

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; }
    }

and as you can see, my model allows me to have sub-questions to a question. and this is how i try to implement it...

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();

and after i am able to save the first sub-question, the second question throws an error at...

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

saying...

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.

i have even tried using IDisposable on GenericRepository without luck...Any hint smelling assistance will be highly appreciated...

1
0
9/23/2015 11:32:52 AM

Popular Answer

i created a UnitOfWork from this example...

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);
        }
    }

then i changed each repository to accept a context...

public class FooRepository :
    GenericRepository<Foo>, IFooRepository {

    public FooRepository(DbContext context) : base(context) {}
}
1
9/25/2015 10:53:49 AM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow