簡體   English   中英

具有存儲庫模式的實體框架插入多對多

[英]Entity Framework with Repository Pattern insert many-to-many

我繼承了一個使用Entity Framework和Repository Pattern的解決方案。 在這個解決方案中,以前的開發人員忘記實現多對多關系,所以現在我必須這樣做。

我不太熟悉EF或模式​​,所以我無法得到我想要實現的工作,即插入多對多關系。 我可以讓EF在數據庫中創建關系表,但不知何故我無法插入它。

我已經看到了與此類似的其他問題 ,但它們都沒有完全匹配模式在這里實現的方式,然后我對一切都不熟悉,無法繞過它。

有人可以看看代碼,看看我錯過了什么? (代碼已經簡化了一點,這不是實際的學生/課程項目,但我使用的是這些名稱,因為它們已在之前的例子中使用過)

這是我的代碼。 非常簡化,沒有數千個接口。 這沒有例外,運行得很好。 當我在“Main”類中調試和快速監視studentUow時,Students.Courses集合確實包含一個值,但它永遠不會保存到數據庫中。 此外,它只包含一個值,即使它應包含多個課程。

實體類

public class Student { // This class already existed
    public int StudentId { get; protected set; }
    public virtual ICollection<Course> Courses { get; set; } // I added this property
}

public class Course { // This class already existed
    public int CourseId { get; protected set; }
    public virtual ICollection<Student> Students { get; set; } // I added this property
}

知識庫

public class StudentRepository {
    protected DbContext DbContext { get; private set; }
    protected DbSet<Student> DbSet { get; private set; }
    public StudentRepository(DbContext dbContext) {
        DbContext = dbContext;
        DbSet = dbContext.Set<Student>();
    }

    public virtual void AddOrUpdate(Student entity) {
        if (Exists(entity)) {
            Update(entity);
        } else {
            Add(entity);
        }
    }

    public virtual void Update(Student entity) {
        var dbEntityEntry = DbContext.Entry(entity);
        if (dbEntityEntry.State == EntityState.Detached) {
            DbSet.Attach(entity);
        }
        dbEntityEntry.State = EntityState.Modified;
    }

    public virtual Student Add(Student entity) {
        var dbEntityEntry = DbContext.Entry(entity);
        if (dbEntityEntry.State != EntityState.Detached) {
            dbEntityEntry.State = EntityState.Added;
        } else {
            return DbSet.Add(entity);
        }
        return null;
    }

    public IQueryable<Student> Queryable() {
        return DbSet;
    }

    public bool Exists(Student entity) {
        var objContext = ((IObjectContextAdapter)DbContext).ObjectContext;
        object existingEntity;
        var exists = objContext.TryGetObjectByKey(GetEntityKey(entity), out existingEntity);
        if (exists) objContext.Detach(existingEntity);

        return exists;
    }

    private EntityKey GetEntityKey(Student entity) {
        var objContext = ((IObjectContextAdapter)DbContext).ObjectContext;
        var objSet = objContext.CreateObjectSet<T>();
        var entityKey = objContext.CreateEntityKey(objSet.EntitySet.Name, entity);
        return entityKey;
    }
}

工作單位

public class StudentUow : UnitOfWork<MyDbContext> {
    public StudentRepository Students { get { return CreateRepository<StudentRepository>(); } }
    public CourseRepository Courses { get { return CreateRepository<CourseRepository>(); } }
}

public class UnitOfWork<TContext> where TContext : System.Data.Entity.DbContext {
    private readonly TContext _dbContext;
    private IRepositoryProvider _repositoryProvider;

    protected UnitOfWork(IRepositoryProvider provider) {
        _repositoryProvider = provider;
    }

    protected TRepository CreateRepository<TRepository>() {
        return _repositoryProvider.Create<TRepository>(_dbContext, "default");
    }

    public void Commit() {
        _dbContext.SaveChanges();
    }
}

[Export(typeof(IUnitOfWorkProvider))]
[PartCreationPolicy(CreationPolicy.Shared)]
public class UnitOfWorkProvider {
    [Import] private IRepositoryProvider _repositoryProvider;

    public StudentUow GetStudentUow() {
        return new StudentUow(_repositoryProvider);
    }
}

[Export(typeof(IRepositoryProvider))]
public class MyRepositoryProvider {
    public MyRepositoryProvider() {
        Register<RepositoryFactory<IProductRepository, StudentRepository>>();
    }

    public TRepository Create<TRepository>(DbContext dbContext, string conntextKey)
    {
        var type = typeof (TRepository);
        if (!_factories.ContainsKey(type))
            throw new UnknownFactoryException(type);

        return (TRepository)_factories[type].Create(dbContext);
    }

    public void Register<TRepositoryFactory>() where TRepositoryFactory : IRepositoryFactory, new()
    {
        var factory = new TRepositoryFactory();
        if (_factories.ContainsKey(factory.Type)) throw new FactoryTypeAlreadyRegisteredException(factory.Type);
        _factories[factory.Type] = factory;
    }
}

“主要”課程

public class MyClass {
    public AddCourse(int studentId, List<int> courses) {
        using (var studentUow = new StudentUow()) {
            foreach (int courseId in courses) {
                Student s = studentUow.Student.Queryable().First(x => x.StudentId == studentId);
                Course c = studentUow.Course.Queryable().First(x => x.CourseId == courseId);
                s.Courses.Add(c);

                studentUow.Student.AddOrUpdate(s);
            }
            studentUow.Commit();
        }
    }
}

如果您遺漏了某些功能,請發表評論,然后我會添加它,或者讓您知道它在哪里。

默認情況下,EF不在查詢中包含相關實體。 為此,您需要在需要時手動包含課程。 還有一個問題是,在每次迭代中,您一次又一次地取回學生,因此課程集合丟失了。 這應該工作:

using System.Data.Entity;
...
using (var studentUow = new StudentUow()) {
    Student s = studentUow.Student.Queryable().Include(x => x.Courses).First(x => x.StudentId == studentId);
    foreach (int courseId in courses) {
        Course c = studentUow.Course.Queryable().First(x => x.CourseId == courseId);
        s.Courses.Add(c);
        c.Students.Add(s);

        studentUow.Course.Update(c);
    }
    studentUow.Student.Update(s);
    studentUow.Commit();
}

如果可能的話,我強烈建議您重構代碼。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM