2017-03-11 31 views
1

我有一個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; } 
} 

映射:

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

} 

通用存儲庫:

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

現在,如果我想加入標準的多對多表,我怎麼能夠做到這一點?

+1

我看到這個問題一遍又一遍地出現,但仍然不明白爲什麼人們在EF中使用通用存儲庫模式。對我來說完全沒用,正如你所看到的只會帶來不必要的頭痛。 – Evk

+0

請問您能澄清一下您的問題嗎?我不明白你想如何加入這兩張表,或者爲什麼。 –

+0

@Evk所以你建議不要使用通用存儲庫?我可以問爲什麼 – Valkyrie

回答

6

所以根據你的編輯,我假設你想加入學生和標準。

您必須做的第一件事是更改存儲庫,以便它不會實例化上下文。你應該把它傳遞作爲參數,參照保存它:

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

你必須做的第二件事是改變你的資料庫來改變GetAll()方法返回IQueryable<T>而不是ICollection<T>

然後改變的GetAll()實現:

return dbSet; 

這樣,你只能得到一個查詢,而不是所有實體的評估名單。然後你就可以做的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(); 
} 

有了這個,你得到studentToStandardIQueryable<T>,這將在數據庫中,一旦您調用運行ToList()就可以了。請注意,您必須將相同的上下文傳遞給兩個存儲庫才能使其工作。

我建議您查看Unit Of Work設計模式。處理多個存儲庫時,它會有很大的幫助。

https://docs.microsoft.com/en-us/aspnet/mvc/overview/older-versions/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application

這是處理事務更有條理和更好的維護的方式,當涉及到多個實體集,並促進關注更好的分離。

希望我正確理解你的問題,這有助於。

+1

「儲存庫」的確切用途是什麼? – Evk

+2

我只是想回答這個問題:使用庫時連接。 我同意,在他們自己的respositories不是很有用。這就是爲什麼我包含了一個鏈接到UoW的實現。添加UoW,添加一些接口並使用DI容器,並且可以完全將BLL與DAL分開。根據我的經驗,這很好,因爲您可以比DbContext更容易地模擬您的接口進行測試,並且可以替換整個數據訪問技術。我們之前在我們的項目中使用了這個功能,現在我們可以轉向EFCore並享受性能優勢,而無需重新測試BLL。 –

+0

@AkosNagy先生爲你解釋了我的投票。這正是我要做的,使用UoW和依賴注入模式,我只需要先把它們放在一起。原諒我的要求,但你知道任何關於UoW的良好教程,並依賴注入混合它? – Valkyrie