SOLID原則を適用する際の助けが必要です

asp.net-mvc dapper entity-framework n-tier-architecture oop

質問

本当に "エンタープライズのEF"に関するJuile Lermanの複数形のコースに感銘を受け、デモアプリケーションを構築することに決めました。

私はVS 2012とEF、SQL Server、およびMVCの最新バージョンを使用しています。私はソリッドの原則を適用するデモアプリケーションを構築しています。 DI&単体テストの実装方法をよりよく理解するためにこれを行っています。

私はこのデモアプリケーションにDBの最初のアプローチを使用しました。これにはUserDetailsという名前のテーブルが1つしか含まれていませんが、SQL Serverでどのように見えるかは次のとおりです。この表をCRUD操作に使用します。 ここに画像の説明を入力

以下は私のアプリケーションを階層化したものです:

1. WESModelソリューション:このレイヤーには、以下のようなModel1.edmxファイルとコンテキストクラスが含まれています。

namespace WESModel
{
    using System;
    using System.Data.Entity;
    using System.Data.Entity.Infrastructure;
    using WESDomain;

    public partial class WESMVCEntities : DbContext
    {
        public WESMVCEntities()
            : base("name=WESMVCEntities")
        {
        }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            throw new UnintentionalCodeFirstException();
        }

        public DbSet<UserDetail> UserDetails { get; set; }
    }
}

2. WESDomainソリューション:このレイヤーには、私のドメインクラス(またはPOCOクラス)が含まれています。これらのPOCOクラスは、実際に私のWESModelレイヤーで自動生成されました。私はそれらをこの層に移動しました。ここでは、単一のPOCOクラスの外観を示します。

namespace WESDomain
{
    using System;
    using System.Collections.Generic;

    public partial class UserDetail:IUserDetail
    {
        public int Id { get; set; }
        public string UserName { get; set; }
    }
}

3:WESDataLayerソリューション:このレイヤーには、上記の2つのレイヤーからのdllへの参照が含まれています。このレイヤーには、次のようなRepositoryクラスがあります。今のところ、私はIRepositoryを同じクラスに保っています:)

namespace WESDataLayer
{ 
    public class UserDetailRepository : IUserDetailRepository
    {
        WESMVCEntities context = new WESMVCEntities();

        public IQueryable<IUserDetail> All
        {
            get { return context.UserDetails; }
        }

        public IQueryable<IUserDetail> AllIncluding(params Expression<Func<IUserDetail, object>>[] includeProperties)
        {
            IQueryable<IUserDetail> query = context.UserDetails;
            foreach (var includeProperty in includeProperties) {
                query = query.Include(includeProperty);
            }
            return query;
        }

        public IUserDetail Find(int id)
        {
            return context.UserDetails.Find(id);
        }

        public void InsertOrUpdate(UserDetail userdetail)
        {
            if (userdetail.Id == default(int)) {
                // New entity
                context.UserDetails.Add(userdetail);
            } else {
                // Existing entity
                context.Entry(userdetail).State = EntityState.Modified;
            }
        }

        public void Delete(int id)
        {
            var userdetail = context.UserDetails.Find(id);
            context.UserDetails.Remove(userdetail);
        }

        public void Save()
        {
            context.SaveChanges();
        }

        public void Dispose() 
        {
            context.Dispose();
        }
    }

    public interface IUserDetailRepository : IDisposable
    {
        IQueryable<IUserDetail> All { get; }
        IQueryable<IUserDetail> AllIncluding(params Expression<Func<UserDetail, object>>[] includeProperties);
        UserDetail Find(int id);
        void InsertOrUpdate(UserDetail userdetail);
        void Delete(int id);
        void Save();
    }
}

4:ConsoleApplication1解決策 :これは私のUIレイヤーです。私の最終的なアプリケーションでは、私のMVCアプリケーションになります。ここで私は単にDBに照会し、データを表示します。これがコードの外観です。

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
             IUserDetailRepository repo = new UserDetailRepository();

             var count = repo.All.ToList().Count().ToString();
             Console.WriteLine("Count: {0}", count);
             Console.ReadLine();

        }
    }
}

質問:私のUIレイヤにはEF DLLの参照がありません。ただし、Repositoryクラスのインスタンスがあります。 MVCアプリケーションでは、コントローラにリポジトリクラスまたはUnitOfWorkのインスタンスがあります。

a)これは正しいことですか?

b)抽象化できる方法はありますか?

c)将来、Dapperや他のORMツールとEFを交換したいのですが?

d)DIツールをこのプロジェクトにどのように適合させるのですか?それはどの層にあるべきですか?

e)ユニットテスト。私はStructureMapを知っていて、今後このプロジェクトをNinjectと交換できるような方法でこのプロジェクトで利用したいと思っています。どのように私はこれを達成するのですか?

この大きな質問をお読みいただきありがとうございます。誰かが私を正しい方向に向けることができればと感謝しています。

受け入れられた回答

質問:私のUIレイヤにはEF DLLの参照がありません。ただし、Repositoryクラスのインスタンスがあります。 MVCアプリケーションでは、コントローラにリポジトリクラスまたはUnitOfWorkのインスタンスがあります。

はい、UIレイヤークラスにはEFへの参照があってはなりません。しかし、これを行うには、具体的なリポジトリへの参照を持つことはできません。 MVCアプリケーションでは、サービスレイヤーを使用しない場合、コントローラーはIUserDetailRepositoryの参照のみを持ち、具体的なタイプを構築から待ちます。 UnitOfWorkについては、あなたの実装に依存します:-)

a)これは正しいことですか?

そうするべき正しいことは「疎結合」と呼ばれ、あなたのデザインがこのように選択しているようです。

b)抽象化できる方法はありますか?

はい、依存関係解決者を使用できます。この方法では、具体的な型を参照する必要はなく、抽象に基づいたコードしか持たない

c)将来、Dapperや他のORMツールとEFを交換したいのですが?

たとえば、IXxxRepository契約の具体的な実装を含むライブラリなどのデータアクセスレイヤが必要です。あなたの場合、それはEFの実装になります。 Dapperのために変更する場合は、このレイヤーを再実装する必要があります。リファクタリングには許容限度があります。

d)DIツールをこのプロジェクトにどのように適合させるのですか?それはどの層にあるべきですか?

DIツールを置くのに最適な場所はUIレイヤーになります。アプリケーションを起動すると、依存関係のバインディングが構成され、すべてが自動的に動作します。

e)ユニットテスト。私はStructureMapを知っていて、今後このプロジェクトをNinjectと交換できるような方法でこのプロジェクトで利用したいと思っています。どのように私はこれを達成するのですか?

依存関係リゾルバーのプラグを外して他のプラグを差し込みたいですか?問題はありません。あなたのアプリケーションとの最小の結合を持つようにDRの設定をコーディングするときに予測してください。場合によっては結合を制限するヒントがいくつかあります...私が現在取り組んでいるプロジェクトでは、まずMVCアプリケーションとサービスレイヤー、ビジネスレイヤー、データアクセスレイヤー、インフラストラクチャーレイヤーがあります。私たちはDRとしてNinjectを使用しており、インフラストラクチャとWeb UIレイヤーだけがNinjectのリファレンスを持っています。プラグを抜くのはとても簡単です。すでにこの方法でUnityを試しました。

もう一つ、UserDetailの契約を結んではいけません。その必要はありません.DTOのよ​​うなすべてのクラスではなく、ステートレスクラスでDependency Injectionを使用します。


人気のある回答

明示的な変数タイピングの代わりに暗黙の変数型を使用する(つまり、 varキーワードを削除する)場合、依存関係をはるかに簡単に判断できます。可能であれば、クラス( UserDetailRepository )の使用よりもインターフェイス( IUserDetailRepository )を使用することをおUserDetailRepositoryます。

例:

1)コンパイラによる型の決定

var repo = new UserDetailRepository();

2)クラス参照によって決定されるタイプ

UserDetailRepository repo = new UserDetailRepository();

3)インタフェースによって決まるタイプ

IUserDetailRepository repo = new UserDetailRepository();

コンパイラではなくインタフェースで型を決定できるようにすることで、同じインタフェース(つまり、 IUserDetailRepository repo = new DapperUserDetailRepository();準拠した異なる参照でスワップできIUserDetailRepository repo = new DapperUserDetailRepository();

また、特定のIoCコンテナ( NinjectCastleWinsorUnityなど)を使用して依存関係を自動的に解決する練習であるInversion of Control(IoC)という境界の上にいるため、 newキーワード直接。

StructureMapに言及したので、ここでその動作の例を示します:

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            IContainer container = ConfigureDependencies();
            IUserDetailRepository repo = container.GetInstance<IUserDetailRepository>();

            var count = repo.All.ToList().Count().ToString();
            Console.WriteLine("Count: {0}", count);
            Console.ReadLine();

        }

        private static IContainer ConfigureDependencies() {
            return new Container(x =>{
                x.For<IUserDetailRepository>().Use<UserDetailRepository>();
            });
        }
    }
}


ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow