2

私たちのアプリケーションでは、リポジトリパターンを使用して、データストレージメディアからデータを取得して保持します。使用することを選択したメディアはEntity Framework 4です。これは非常にクリーンな方法で、99%の時間を費やしています。Entity FrameworkのデータコンテキストをWebアプリケーションに集中させるにはどうすればよいですか?

今、問題が発生しています。

public class UserRepository : IUserRepository 
{ 
    Entities dataContext = new Entities(); 

    public User GetUser(string username) 
    { 
     return dataContext.Users.SingleOrDefault(x => x.Username == username); 
    } 

    // ... more CRUD-style methods that are not relevant to this question. 

    public void SaveChanges() 
    { 
     dataContext.SaveChanges(); 
    } 
} 

public RoleRepository : IRoleRepository 
{ 
    Entities dataContext = new Entities(); 

    public Role GetRole(string name) 
    { 
     return dataContext.Roles.SingleOrDefault(x => x.Name == name); 
    } 

    // ... more CRUD-style methods that are not relevant to this question. 

    public void SaveChanges() 
    { 
     dataContext.SaveChanges(); 
    } 
} 

ユーザーとロールが実際にEntity Frameworkのモデルでは、多くの関係に多くを持っている:私たちは、このような2つのリポジトリを持っています。時には、既存のユーザーと既存の役割を引き継いで、その2つを関連づけたい場合もあります。両方のエンティティが同じEFデータコンテキストオブジェクトから取得されているので、これは素晴らしい作品

Entities dataContext = new Entities(); 
Role roleToAdd = dataContext.Roles.Single(x => x.Name == "Admin"); 
User user = dataContext.Users.Single(x => x.Username == "Fred"); 
user.Roles.Add(roleToAdd); 
dataContext.SaveChanges(); 

:あなたはこのように短いサンプルコードスニペットを行う場合、通常、これは素晴らしい仕事です。しかし、我々のアプリケーションでは、各リポジトリは独自のデータコンテキストオブジェクトを作成します。だから我々は我々自身のアーキテクチャと上記と同じことをしようとすると:

UserRepository userRepo = new UserRepository(); 
RoleRepository roleRepo = new RoleRepository(); 
User user = userRepo.GetUser("Fred"); 
Role roleToAdd = roleRepo.GetRole("Admin"); 
user.Roles.Add(roleToAdd); 
userRepo.SaveChanges(); 

私たちは、このエラーを取得する:

The relationship between the two objects cannot be defined because they are attached to different ObjectContext objects.

このデータコンテキストを一元化するための最良の方法は何ですか?明らかに、私はUserRepository内でGetRoleメソッドを複製したくないのです。なぜなら、それは冗長で愚かなためです。私は、ユーザー名とロール名になりますUserRepositoryに、より詳細な方法を行うことができ、このように、取得し、それらを関連付けるために同じデータコンテキストを使用しています。

public void AddUserToRole(string username, string role) 
{ 
    User user = dataContext.Users.Single(x => x.Username == username); 
    Role roleToAdd = dataContext.Roles.Single(x => x.Name == role); 
    user.Roles.Add(roleToAdd); 
} 

私はその後、ちょうど行うことができます:

userRepo.AddUserToRole("Fred", "Admin"); 
userRepo.SaveChanges(); 

これを達成するための最善の方法はありますか?すべてのリポジトリが独自のリポジトリを作成するのではなく、同じリポジトリを使用するように、各リクエストにEFデータコンテキストを集中させるより良い方法はありますか?もしそうなら、どうすればいいのですか?

何か助けていただければ幸いです。

答えて

7

コンテキストを渡すためにリポジトリにコンストラクタインジェクションを使用します。

public class UserRepository : IUserRepository 
{ 
    Entities dataContext; 

    public UserRepository(Entities entities) 
    { 
     this.dataContext = entities; 
    } 

    public User GetUser(string username) 
    { 
     return dataContext.Users.SingleOrDefault(x => x.Username == username); 
    } 

    // ... more CRUD-style methods that are not relevant to this question. 

    public void SaveChanges() 
    { 
     dataContext.SaveChanges(); 
    } 
} 

DIコンテナーにコンテキストライフタイムを要求するように指示します。 AutoFacと

例えば、あなたが希望:

builder.RegisterType<Entities>().InstancePerHttpRequest(); 
builder.RegisterType<UserRepository>().As<IUserRepository>().InstancePerHttpRequest(); 
builder.RegisterControllers(typeof(MvcApplication).Assembly); 
+3

なぜ私はそれを考えなかったのですか? 'kernel.Bind .ToSelf().InRequestScope()'がトリックをしました!ありがとうございました。 – Chev

+0

私たちはNinjectを使用していますが、同じ概念が美しく適用されます。 6分で受け入れます。 – Chev

+0

ひとつ追加します。 'IUserRepository.SaveChanges()'には注意してください。 'User'だけでなく、全体の要求を原子的に保存するようになりました。それはおそらく*あなたが望むものですが、それがその範囲にある場合は明白ではないかもしれません。 –

0

個人的には、ユーザー名と役割を渡し、データベースにユーザーを追加するためのリポジトリ内のすべてのdbロジックを持つ方法が好きです。このメソッドを10回呼び出した場合、MVCアプリケーション内の10の異なる場所にある役割を取得してユーザーオブジェクトに追加することは望ましくありません。

すべての作業をリポジトリに任せます。

+0

私は同意しません。私たちのアプリケーションは3つのレイヤーに分かれています。 UI、ビジネス、およびデータ。リポジトリが大変な作業をしているのは嫌です。私はむしろ、そのようなロジックをビジネス層のコントローラークラスに集中させたいと思っています。私たちの目標は、リポジトリをできるだけ無関係な関係に保つことです。 – Chev

関連する問題