如何使用通用存储库模式的连接 - 实体框架

Val*_*rie 1 c# entity-framework unit-of-work repository-pattern

我有一个Generic Repository像下面的处理我的CRUD,对于一个单一的实体它易于使用,问题开始时,我尝试加入我的POCOs.

假设我有这些POCO,它们使用流畅的api(多对多和一对多关系)进行映射:

public class Student
{
    public Student() 
    {
        this.Courses = new HashSet<Course>();
    }

    public int StudentId { get; set; }
    public string StudentName { get; set; }

    //FKs 
    public virtual Standard Standard { get; set; }
    public int StdandardRefId { get; set; }

    public virtual ICollection<Course> Courses { get; set; }
}

public class Course
{
    public Course()
    {
        this.Students = new HashSet<Student>();
    }

    public int CourseId { get; set; }
    public string CourseName { get; set; }

    public virtual ICollection<Student> Students { get; set; }
}
public class Standard
{
    public Standard()
    {
        Students = new List<Student>();
    }
    public int StandardId { get; set; }
    public string Description { get; set; }

    public virtual ICollection<Student> Students { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

制图:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    //Many-To-Many
    modelBuilder.Entity<Student>()
                .HasMany<Course>(s => s.Courses)
                .WithMany(c => c.Students)
                .Map(cs =>
                        {
                            cs.MapLeftKey("StudentRefId");
                            cs.MapRightKey("CourseRefId");
                            cs.ToTable("StudentCourse");
                        });
        //One-To-Many
        modelBuilder.Entity<Student>()
                .HasRequired<Standard>(s => s.Standard)
                .WithMany(s => s.Students)
                .HasForeignKey(s => s.StandardId);

}
Run Code Online (Sandbox Code Playgroud)

通用存储库:

public class Repository<T> : IRepository<T>
    where T : class, IDisposable
{
    internal MyDbContext context;
    internal DbSet<T> dbSet;

    public Repository()
    {
        context = new MyDbContext();
        this.dbSet = context.Set<T>();
    }

    public bool Add(T entity)
    {
        var query = dbSet.Add(entity);

        if (query != null)
            return true;
        return false;
    }

    public bool Update(T entity)
    {
        dbSet.Attach(entity);
        var query = context.Entry(entity).State = EntityState.Modified;

        if (query == EntityState.Modified)
            return true;
        return false;
    }
    public bool Delete(T entity)
    {
        var query = dbSet.Remove(entity);

        if (query != null)
            return true;
        return false;
    }
    public bool Delete(Guid id)
    {
        var query = dbSet.Remove(dbSet.Find(id));

        if (query != null)
            return true;
        return false;
    }
    public T GetById(Guid id)
    {
        var query = dbSet.Find(id);

        if (query != null)
            return query;
        else
            return null;
    }
    public ICollection<T> GetAll()
    {
        return dbSet.AsEnumerable<T>().ToList();
    }

    public void Save()
    {
        context.SaveChanges();
    }
    public void Dispose()
    {
        if (context != null)
        {
            context.Dispose();
            context = null;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,如果我想加入Standard to Many-to-Many Table,我怎么能够做到这一点?

Ako*_*agy 15

因此,基于您的编辑,我假设您想加入学生和标准.

您要做的第一件事是更改存储库,以便它不会实例化上下文.您应该将其作为参数传递并存储对它的引用:

public Repository(MyDbContext myCtx)
{
    context = myCtx;
    this.dbSet = context.Set<T>();
}
Run Code Online (Sandbox Code Playgroud)

您要做的第二件事是更改您的存储库以将GetAll()方法更改为返回IQueryable<T>而不是ICollection<T>.

然后改变执行GetAll():

return dbSet;
Run Code Online (Sandbox Code Playgroud)

这样您只能获得查询而不是所有实体的评估列表.然后你就可以GetAll()像使用数据库集一样使用存储库的方法进行连接:

using (MyDbContext ctx = new MyDbContext())
{
  var studentRep = new Repository<Student>(ctx);
  var standardRep = new Repository<Standard>(ctx);
  var studentToStandard = studentRep.GetAll().Join(standardRep.GetAll(), 
                        student => student.StandardRefId,
                        standard => standard.StandardId,
                        (stud, stand) => new { Student=stud, Standard=stand }).ToList();
}
Run Code Online (Sandbox Code Playgroud)

有了这个,你就会得到一个IQueryable<T>in studentToStandard,一旦你调用它就会在数据库中运行ToList().请注意,您必须将相同的上下文传递给两个存储库才能使其正常工作.

我建议您查看工作单元设计模式.处理多个存储库时,它会有很大帮助.

https://docs.microsoft.com/en-us/aspnet/mvc/overview/older-versions/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-的工作图案,在安-ASP净MVC应用程序

当涉及多个实体集时,这是一种更有条理且更易于维护的处理事务的方式,并促进更好地分离关注点.

希望我能正确理解你的问题,这有帮助.

  • 我只是想回答这个问题:在使用存储库时加入.我同意他们自己的存储库不是很有用.这就是为什么我在UoW中包含了一个实现的链接.添加UoW,添加一些接口并使用DI容器,您可以将BLL与DAL完全分开.根据我的经验,这很好,因为您可以比DbContext更轻松地模拟您的界面进行测试,您可以替换整个数据访问技术.我们之前在项目中使用了这个,现在我们可以转移到EFCore并享受性能优势,而无需重新测试BLL. (3认同)