需要帮助申请SOLID原则 [英] Need Help in applying SOLID principles

查看:123
本文介绍了需要帮助申请SOLID原则的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

与Juile勒曼的pluralsight当然pssed上的企业EF和

真的IM $ P $决定建立我的演示应用程序。

我使用VS 2012和EF,SQL Server和MVC的最新版本。我建立适用SOLID原则的演示应用程序。我这样做是为了更好地了解如何实施DI&安培;单元测试。

我已经使用DB第一种方法为这个演示应用程序。它仅包含一个表命名的UserDetails以下是如何看起来在SQL服务器。我将使用这个表CRUD操作。

下面是如何我已经分层我的应用程序:

1。 WESModel解决方案:这一层包含了我Model1.edmx文件,如下上下文类

 命名空间WESModel
{
    使用系统;
    使用System.Data.Entity的;
    使用System.Data.Entity.Infrastructure;
    使用WESDomain;    公共部分类WESMVCEntities:的DbContext
    {
        公共WESMVCEntities()
            :基地(NAME = WESMVCEntities)
        {
        }        保护覆盖无效OnModelCreating(DbModelBuilder模型构建器)
        {
            抛出新的意外codeFirstException();
        }        公共DbSet< UserDetail> {的UserDetails获得;组; }
    }
}

2。 WESDomain解决方案:这一层包含我的域名类(或POCO类)。这些POCO类实际上是在我WESModel层自动生成。我搬到他们到这一层。这里是一个POCO类的样子。

 命名空间WESDomain
{
    使用系统;
    使用System.Collections.Generic;    公共部分类UserDetail:IUserDetail
    {
        公众诠释标识{搞定;组; }
        公共字符串用户名{获得;组; }
    }
}

3:WESDataLayer解决方法:这一层包含我的上述2层参考的DLL。
这一层我的仓库类,如下图所示。现在,我保持IRepository在同级别:)

 命名空间WESDataLayer
{
    公共类UserDetailRepository:IUserDetailRepository
    {
        WESMVCEntities语境=新WESMVCEntities();        公众的IQueryable< IUserDetail>所有
        {
            {返回context.UserDetails; }
        }        公众的IQueryable< IUserDetail> AllIncluding(PARAMS前pression<&Func键LT; IUserDetail,对象>> [] includeProperties)
        {
            IQueryable的< IUserDetail>查询= context.UserDetails;
            的foreach(在includeProperties VAR includeProperty){
                查询= query.Include(includeProperty);
            }
            返回查询;
        }        公共IUserDetail查找(INT ID)
        {
            返回context.UserDetails.Find(ID);
        }        公共无效InsertOrUpdate(UserDetail userdetail)
        {
            如果(userdetail.Id ==默认值(INT)){
                //新建实体
                context.UserDetails.Add(userdetail);
            }其他{
                //现有实体
                context.Entry(userdetail).STATE = EntityState.Modified;
            }
        }        公共无效删除(INT ID)
        {
            变种userdetail = context.UserDetails.Find(ID);
            context.UserDetails.Remove(userdetail);
        }        公共无效保存()
        {
            context.SaveChanges();
        }        公共无效的Dispose()
        {
            context.Dispose();
        }
    }    公共接口IUserDetailRepository:IDisposable接口
    {
        IQueryable的< IUserDetail>所有{搞定; }
        IQueryable的< IUserDetail> AllIncluding(PARAMS前pression<&Func键LT; UserDetail,对象>> [] includeProperties);
        UserDetail查找(INT ID);
        无效InsertOrUpdate(UserDetail userdetail);
        无效删除(INT ID);
        无效保存();
    }
}

4:ConsoleApplication1解决方案:这是我的UI层。这将是我最后的应用程序我的MVC应用程序。在这里,我简单地查询数据库,并显示数据。这是code的外观。

 命名空间的ConsoleApplication1
{
    类节目
    {
        静态无效的主要(字串[] args)
        {
             IUserDetailRepository回购=新UserDetailRepository();             。VAR计数= repo.All.ToList()计数()的ToString()。
             Console.WriteLine(计数:{0},计数);
             到Console.ReadLine();        }
    }
}

问:我的UI层没有任何裁判EF DLL。但是,它有库类的一个实例。在MVC应用程序,我的控制器将有仓储类或的UnitOfWork的一个实例。

A)这是应该做的事情吗?

二)有没有什么办法可以抽象吗?

三)我想换出EF与小巧玲珑的或任何其他ORM工具如果在未来?

D)我如何适合在这个项目中我的DI工具?在该层中它应该是什么?

E)单元测试。我知道StructureMap,并想在这个项目中使用它以这样的方式,今后我应该能够Ninject掉出来。我如何实现这一目标?

感谢您阅读这个大问题,我真的AP preciate如果有人能在正确的方向指向我。


解决方案

  

问:我的UI层没有任何裁判EF DLL。然而,它具有
  库类的一个实例。在MVC应用程序,我的控制器
  将有仓储类或的UnitOfWork的一个实例。


是的,UI层类必须不必EF任何引用。但要做到这一点,就可以不必在混凝土库的参考。在MVC应用程序,如果你不使用一个服务层,控制器将只有在IUserDetailRepository参考,并等待从建筑的具体类型。
有关的UnitOfWork,这取决于具体的实现: - )


  

A)这是应该做的事情吗?


做的正确的事情被称为松耦合,似乎你​​的设计是选择这种方式。


  

二)有没有什么办法可以抽象吗?


是的,你可以使用依赖解析器。这样一来,没有必要引用具体的类型,你将有只有基于抽象一个code


  

三)我想换出EF与小巧玲珑的或任何其他ORM工具如果在未来?


您必须有一个数据访问层,例如,包含您IXxxRepository合同的具体实现库。根据你的情况,这将是EF实现。当你将为小巧玲珑改变,你将不得不重新实现这一层。重构有一个可以接受的限度。


  

D)我如何适合在这个项目中我的DI工具?在该层中它应该是什么?


最好的地方,把你的DI工具将UI层。在应用程序启动,您将配置依赖绑定,一切都将自动地工作;)


  

E)单元测试。我知道StructureMap,并想在这个项目中使用它以这样的方式,今后我应该能够Ninject掉出来。我如何实现这一目标?


您想拔下依赖解析器堵塞的其他?没问题,只要有一个预测编码的DR的配置时必须与你的应用程序中的最小耦合。有一些提示,以限制耦合在某些情况下...在这个项目我目前的工作,我们必须先MVC应用程序和服务层,业务层,数据访问层,基础设施层。我们使用Ninject作为DR和infratructure和Web UI层是只对Ninject的参考。这很容易拔掉它,我们已经尝试过统一这样的。

还有一件事,你不应该有UserDetail合同。没有必要为使用依赖注入无状态类,而不是像DTO的所有类。

Really impressed with Juile Lerman's pluralsight course on "EF in Enterprise" and decided to build my demo app.

I am using VS 2012 and latest versions of EF,SQL Server and MVC. I am building a demo application which applies SOLID principles. I am doing this to better understand how to implement DI & unit testing.

I have used DB first approach for this demo application. It contains only one table named UserDetails and below is how it looks in SQL server. I will use this table for CRUD operations.

Below is how i have layered my application :

1. WESModel Solution: This layer contains my Model1.edmx file and the context class as below.

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 Solution: This layer contains my Domain classes (or POCO classes). These POCO classes were actually auto generated in my WESModel layer. I moved them out to this layer. Here is how the single POCO class looks.

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 Solution: This layer contains reference to dlls from my above 2 layers. This layer has my Repository class as shown below. For now , I am keeping the IRepository in the same class :)

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 Solution: This is my UI layer. It will be my MVC application in my final app. Here i simply query the DB and display the data. This is how the code looks.

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

        }
    }
}

Question: My UI layer does not have any ref to EF DLL. However, It has an instance of Repository class. In MVC application, my controller will have an instance of repository class or UnitOfWork.

a) Is this the right thing to do ?

b) Is there any way i can abstract it ?

c) What if in future i want to swap out EF with Dapper or any other ORM tool ?

d) How do i fit my DI tool in this project ? In which layer it should be ?

e) Unit testing. I am aware of StructureMap and want to make use of it in this project in such a way that in future i should be able to swap it out with Ninject. How do i achieve this ?

Thanks for reading this big question and i really appreciate if anyone can point me in right direction.

解决方案

Question: My UI layer does not have any ref to EF DLL. However, It has an instance of Repository class. In MVC application, my controller will have an instance of repository class or UnitOfWork.

Yes, UI layer classes must not have any reference to EF. But to do this, they can't have a reference to the concrete repository. In MVC Application, if you don't use a Service Layer, the Controller will have a reference just on IUserDetailRepository, and wait a concrete type from construction. About UnitOfWork, it depends on your implementation :-)

a) Is this the right thing to do ?

The right thing to do is called "loose coupling", it seems that your design is choosing this way.

b) Is there any way i can abstract it ?

Yes, you can use a Dependency Resolver. This way, no need to reference concrete types, you will have a code only based on abstractions

c) What if in future i want to swap out EF with Dapper or any other ORM tool ?

You must have a Data Access Layer, for example, a library containing your concrete implementations of your IXxxRepository contracts. In your case, it will be EF implementations. When you will change for Dapper, you will have to re-implement this layer. The refactoring has an acceptable limit.

d) How do i fit my DI tool in this project ? In which layer it should be ?

Best place to place your DI tool will be the UI layer. On application start, you will configure dependencies bindings and everything will work automagically ;)

e) Unit testing. I am aware of StructureMap and want to make use of it in this project in such a way that in future i should be able to swap it out with Ninject. How do i achieve this ?

You want to unplug your Dependency Resolver to plug an other? No problem, just have a forecast when coding configuration of your DR to have the minimum coupling with your application. There are some tips to limit coupling in some cases... In the project I am currently working on, we have first an MVC application and a Service Layer, Business Layer, Data Access Layer, and Infrastructure Layer. We use Ninject as DR, and the infratructure and Web UI layers are the only that have a reference on Ninject. It's very easy to unplug it, and we already tried Unity this way.

One more thing, you shouldn't have a contract for UserDetail. There is no need for that, use Dependency Injection on stateless classes rather than on all classes like DTOs.

这篇关于需要帮助申请SOLID原则的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆