通用存储库中的IEntityChangeTracker的多个实例无法引用实体对象

时间:2015-09-23 11:32:53

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

我在这个tugberkugurlu中使用了通用接口和存储库,这是......

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

和这个通用存储库

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

现在可以像这样使用......

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

    public Foo GetSingle(int fooId) {

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

现在,直到我有了一个自引用实体,就像这样......或者很好......

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

正如您所看到的,我的模型允许我对一个问题提出子问题。这就是我试图实现它的方式......

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

并且在我能够保存第一个子问题之后,第二个问题在......

时抛出错误
_ctx.Entry(entity).State = EntityState.Modified;

说...

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.

我甚至尝试在IDisposable上使用GenericRepository但没有运气......任何暗示嗅觉的帮助都将受到高度赞赏......

2 个答案:

答案 0 :(得分:1)

我想你因为背景而有问题。可能你有两个同一个实体的背景。这可能是因为创建了require 'test_helper' class StaticPagesControllerTest < ActionController::TestCase def setup @base_title = "Ruby on Rails Tutorial Sample App" end test "should get home" do get :home assert_response :success assert_select "title", "Ruby on Rails Tutorial Sample App" end test "should get help" do get :help assert_response :success assert_select "title", "Help | #{@base_title}" end test "should get about" do get :about assert_response :success assert_select "title", "About | #{@base_title}" end test "should get contact" do get :contact assert_response :success assert_select "title", "Contact | #{@base_title}" end end 。尝试使用context-per-repository pattern,或者只为所有存储库创建一个上下文。

答案 1 :(得分:1)

我从this example ...

创建了一个UnitOfWork
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);
        }
    }

然后我改变了每个存储库以接受上下文......

public class FooRepository :
    GenericRepository<Foo>, IFooRepository {

    public FooRepository(DbContext context) : base(context) {}
}