3

Juile Lerman の「EF in Enterprise」に関する複数サイト コースに本当に感銘を受け、デモ アプリを作成することにしました。

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

このデモ アプリケーションでは、DB ファースト アプローチを使用しました。UserDetails という名前のテーブルが 1 つだけ含まれており、以下は SQL サーバーでの外観です。このテーブルを 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 への参照が含まれています。このレイヤーには、以下に示すようにリポジトリ クラスがあります。今のところ、同じクラスに 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) 将来、EF を Dapper やその他の ORM ツールと交換したい場合はどうすればよいですか?

d) このプロジェクトに DI ツールをどのように適合させますか? どのレイヤーにあるべきですか?

e) 単体テスト。私は StructureMap を認識しており、将来的に Ninject と交換できるように、このプロジェクトでそれを利用したいと考えています。どうすればこれを達成できますか?

この大きな質問を読んでくれてありがとう。誰かが私を正しい方向に向けることができれば本当に感謝しています。

4

3 に答える 3

2

明示的な変数型付けの代わりに暗黙的な変数型付けを使用する (つまり、varキーワードを削除する) と、依存関係をより簡単に判断できます。IUserDetailRepository可能な限り、クラス ( ) よりもインターフェース ( ) を使用することをお勧めしますUserDetailRepository

例:

1) コンパイラが型を決定できるようにする

var repo = new UserDetailRepository();

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

UserDetailRepository repo = new UserDetailRepository();

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

IUserDetailRepository repo = new UserDetailRepository();

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

また、制御の反転 (IoC) と呼ばれる原則の境界にいます。これは、特定の IoC コンテナー ( NinjectCastleWinsorUnityなど) を使用して依存関係を自動的に解決する方法であり、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>();
            });
        }
    }
}
于 2013-07-27T16:09:55.230 に答える
0

簡単に言うと:

モデルには、データを永続化したり、クエリを実行したりするための依存関係がありIRepositoryます (IRepository の実装は、Dapper、EF、ADO.Net など、何でもかまいません)。モデルにはビジネス ルールがあります。

ビュー (コンソール、WPF、Web) は、ビューとモデルの間のレイヤーpresenter(MVP)、controller(MVC)、またはviewmodel(MVVM) に依存しています。

その中間層はモデルと連携してデータを永続化します。

依存ポイントを使用して DI を使用できます。

単体テストはどのレイヤーにも適用できますが、ビジネス ルールを特別にカバーするようにしてください。

IUserDetailRepositoryリポジトリのように見え、モデルはそれを使用する必要があります。このようにして、インターフェイスの抽象化の背後にあるデータベースの実装を分離します。前述のように、実際の実装は EF や dapper などのようなものになる可能性があります。

MVC モデルでは、コントローラーはモデルを呼び出して、ビジネス ルールを適用し、データを保持します。

于 2013-07-27T14:56:59.927 に答える