0

Entity Framework、Repositories、および IOC を学習して、私が達成しようとしているのは、データ ソース プロバイダーを変更するためにリポジトリ パターンを実装することです。

オープンソース プロジェクトからのこの例を参照してください。

namespace MyApp.Domain.Interfaces
{
    public interface IEFContext : IDisposable
    {
    }
}

EFContext (IEFContext の実装)

namespace MyApp.Data.Context
{
    public class EFContext : DbContext, IEFContext
    {
        public const string DBConnectionName = @"MyDBName";

        public EFContext() : base(DBConnectionName)      
        {
        }

        public DbSet<Member> Member { get; set; }
    }
}

IMemberRepository

namespace MyApp.Domain.Interfaces.Repositories
{
    public interface IMemberRepository
    {
        Member GetUser(string username);
    }
}

MemberRepository (IMemberRepository の実装)

namespace MyApp.Data.Repositories
{
    public class MemberRepository : IMemberRepository
    {
        private readonly EFContext _context;

        public MemberRepository(IEFContext context)
        {
            _context = context as EFContext;
        }

        // update
        public Member GetUser(string username)
        {
            return _context.Member.SingleOrDefault(name => name.UserName.ToUpper().Contains(username.ToUpper()));
        }
    }
}

これは Unity を使用した私のアプリケーション コンソールです

コンソール アプリ

namespace MyApp.ConsoleApp
{
    public class Program
    {
        static void Main(string[] args)
        {
            var container = new UnityContainer();
            container.RegisterType<IEFContext, EFContext>();
            container.RegisterType<IMemberRepository, MemberRepository>();
            var repository = container.Resolve<MemberRepository>();
            var user = repository.GetUser("johnDoe");
            Console.WriteLine(user.Email);
            Console.ReadLine();
        }
    }
}

私の質問は次のとおりです。

次のような新しいコンテキストを追加することにした場合:

namespace MyApp.Data.Context
{
    public class EFContext2 : DbContext, IEFContext
    {
        public const string DBConnectionName = @"MyNewDBName";

        public EFContext2() : base(DBConnectionName)      
        {
        }

         public DbSet<Member> Member { get; set; }
    }
}

次のように依存関係を変更するだけでよいはずです。

namespace MyApp.ConsoleApp
{
    public class Program
    {
        static void Main(string[] args)
        {
            ...
            container.RegisterType<IEFContext, EFContext2>();
            ...         
        }
    }
}

しかし、この例では、MemberRepository は最初のコンテキストと疎結合です。したがって、コンテキストを変更する必要がある場合は、リポジトリも変更する必要があります。

この点について、ご意見をいただければ幸いです。敬具

4

1 に答える 1

5
but in this example my MemberRepository is loosely-coupled with my first context. So if I have to change my Context I must also change my repository.

はい、そうですが、次の1 行の変更です。

private readonly EFContext _context;  

private readonly IEFContext _context;  

コンストラクターにキャストしない:

public MemberRepository(IEFContext context)            
{                
    _context = context;            
}

これで、IEFContext を実装するあらゆる種類の具象コンテキストを注入できます。

これについて考えてみてください。依存性注入でやろうとしていることは、まあ、依存性を注入することです。しかし、どうやってそれを行うのですか?それを行うには、これらの依存関係を一般化します。つまり、別のコンテキストを使用できるようにしたい場合IEFContextは、具体的なコンテキストの代わりにインターフェイスを使用します。そのため、コンストラクターはインターフェイスを必要とします。

しかし、それは最初の部分です。あなたのコードの問題は、

_context = context as EFContext;

インターフェイスをダウンキャストして、次のように言っています。このインターフェイスは EFContext です。あなたは一般性を失っています。たとえば、SQLContextを注入しようとすると、IEFContextであってもEFContextではないため、注入できないことを知っておいてください。as EFContextそのため、パーツを取り外して放置するだけです

_context = context;

2番目の部分については、一般的であり、インターフェースを期待して受け取ることは、最初の部分にすぎません。ここで、ジェネリック コンテキスト IEFContext を期待していることをコンパイラに伝える必要がありますが、どのコンテキストを受け取っても、たとえば GetUsers を実行できるはずであることも伝える必要があります。そこで、インターフェースの出番です。インターフェイス内でプロパティを宣言し、public Member GetUser{}どのコンテキストが到着してもユーザーを取得できることを強制および保証します。

これが少し簡単に理解できることを願っています。幸運を。

于 2012-09-22T16:42:03.717 に答える