2017-03-11 10 views
1

私は、を私のCRUDとして扱いました。単一のエンティティで使いやすいので、私がPOCOsに参加しようとすると問題が発生します。ジェネリックリポジトリパターンでの結合の使い方 - Entity Framework

は、彼らは(多くの関係に多くの多くとワン)流暢なAPIを使用してマッピングされ、私はこれらのPOCOを考えてみましょう:

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

少し質問を明確にしてください。私はあなたがこれらの2つのテーブルをどのようにして参加したいのか、なぜそうは見ませんか? –

+0

@ Evkので、汎用リポジトリを使用しないことをお勧めしますか?私はなぜ尋ねるかもしれません – Valkyrie

答えて

6

あなたの編集に基づいて、私はあなたが学生とスタンダードに参加したいと思っています。

まず、コンテキストをインスタンス化しないようにリポジトリを変更する必要があります。あなたがしなければならない二つ目はIQueryable<T>代わりのICollection<T>を返すようにGetAll()方法を変更するリポジトリを変更され

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

:あなたは、パラメータとしてそれを渡すと、それへの参照を格納する必要があります。

その後GetAll()の実装を変更:

return dbSet; 

あなただけのクエリではなく、すべてのエンティティの評価を行っ一覧を取り戻すこの道を。あなたが呼び出す一度データベースで実行されますstudentToStandardIQueryable<T>を取得これにより

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

:そして、あなたはデシベルセットでそれを行うのと同じように、リポジトリのGetAll()方法で参加を行うことができますそれには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-of-work-patterns-in-an-asp-net-mvc-application

これは、複数のエンティティセットになるとハンドリング取引のより構造化され、より良いメンテナンス性の方法である、との懸念の良好な分離を促進します。

私はあなたの問題を正しく理解しており、これが役に立ちます。

+1

「リポジトリ」はここではどのような目的で使用されますか? – Evk

+2

私はちょうど質問に答えることを試みていた:リポジトリを使用するときの結合。 私は、自分のリポジトリではそれほど有用ではないことに同意します。そのため、私はUoWで実装にリンクしました。 UoWを追加し、いくつかのインターフェイスを追加してDIコンテナを使用すると、BLLとDALを完全に分離することができます。私の経験では、これは良いことです。なぜなら、テストのためにDbContextよりも簡単にインターフェースをモックでき、データアクセス技術全体を置き換えることができるからです。私たちはこれを以前のプロジェクトで使っていましたが、今度はBLLを再テストせずにEFCoreに移行してパフォーマンスのメリットを享受することができます。 –

+0

@AkosNagyよくあなたのために私の投票を説明しました。それはちょうど私が行っている、UoWと依存性注入パターンを使用して、私はちょうど一緒に作品を右に取得する必要があります。私に尋ねてくれたことを許しますが、あなたはUoWに関する良いチュートリアルを知っていて、それを依存性注入と混ぜていますか? – Valkyrie

関連する問題