.NET管理层关系

我实际上是在重新创建项目的默认架构。 在这篇文章中,我希望你不仅可以帮助我,还可以思考,讲述和改进现有方法。 这可能是非常有用的挑战。 此默认架构可以与所有人自由共享。 所以这里是描述:基本上MVC是我们的观点。 我们遵循OOP和层编程概念。 我们还将使用SQL ServerEF DB First 。 所以这就是我到目前为止所做的:我在我的解决方案中创建了4个层:

  1. 域:JUST域类
  2. DAL:负责访问数据,包含UOW和存储库以及与数据访问相关的validation。
  3. BL:独特负责业务逻辑和DAL的独特老板。
  4. UI:这不是那么重要! (即使它可能是一个控制台应用程序!)

我已经使用通用函数实现BL,如getAll和getById以及crud funcs.these funcs将调用DAL通用函数,这也是准备好的。 现在一个重要的问题是:将DAL函数实现为GENERIC是否正确? 请考虑这种情况:

从UI我们发布模型到动作,在行动中我们称为BL Func( BL.insert (模型))。 BL.Insert函数会调用类似DAL.Add (模型)的东西(注意BL将调用DAL一次并告诉它它想要什么)。 现在DAL.Add func必须将3条记录插入3个不同的表中(模型从UI层传递)。 我认为这不可能通过DAL GENERICfunction来实现。 那么,在注意到关注点分离的情况下,实现图层和关系的正确和标准方法是什么?

在我的行动中我会:

 [HttpPost] public ActionResult Insert() { Bl.EntityBase.Article.Insert(new Article()); return RedirectToAction("Index"); } 

在BL我会:

 public void Insert(T obj) { Da.Repository().Insert(obj); } 

在我的DAL中,我有:

 public virtual void Insert(T entity) { DbEntityEntry dbEntityEntry = Db.Entry(entity); if (dbEntityEntry.State != EntityState.Detached) { dbEntityEntry.State = EntityState.Added; } else { Set.Add(entity); } } 

如果您通过BL传递给DAL的模型是视图模型,则逻辑将在您的DAL中,否则您不应传递将为3个不同的表执行3次插入的模型。

您应该在DAL中使用通用存储库实现存储库模式。 为了放置抽象,你必须使用IRepository接口,它的实现应该使用依赖项解析器注入。 您也可以使用界面在BL(服务)中实现相同的function。

这是一个很好的讨论: 存储库和服务层之间的区别?

您还可以使用“工作单元”模式对其进行改进。

这是一个完整的代码片段,展示了如何在多个层之间实现抽象:


知识库

 public interface IRepository where T : class { DbContext GetContext(); IQueryable GetAll(); IQueryable FindBy(Expression> predicate); void Add(T entity); void Delete(T entity); void DeleteAll(IEnumerable entity); void Edit(T entity); bool Any(); } 

 public class Repository : IRepository where T : class { private readonly DbContext _context; private readonly IDbSet _dbset; public Repository(DbContext context) { _context = context; _dbset = context.Set(); } public virtual DbContext GetContext() { return _context; } public virtual IQueryable GetAll() { return _dbset; } public IQueryable FindBy(Expression> predicate) { var query = _dbset.Where(predicate).AsQueryable(); return query; } public virtual void Add(T entity) { _dbset.Add(entity); } public virtual void Delete(T entity) { var entry = _context.Entry(entity); entry.State = EntityState.Deleted; _dbset.Remove(entity); } public virtual void DeleteAll(IEnumerable entity) { foreach (var ent in entity) { var entry = _context.Entry(ent); entry.State = EntityState.Deleted; _dbset.Remove(ent); } } public virtual void Edit(T entity) { var entry = _context.Entry(entity); _dbset.Attach(entity); entry.State = EntityState.Modified; } public virtual bool Any() { return _dbset.Any(); } } 

UOW

 public interface IUnitOfWork : IDisposable { IRepository GetRepository() where TEntity : class; void Save(); } 

  public class UnitOfWork : IUnitOfWork where TContext : DbContext, new() { private readonly DbContext _ctx; private readonly Dictionary _repositories; private bool _disposed; public UnitOfWork() { _ctx = new TContext(); _repositories = new Dictionary(); _disposed = false; } public IRepository GetRepository() where TEntity : class { // Checks if the Dictionary Key contains the Model class if (_repositories.Keys.Contains(typeof (TEntity))) { // Return the repository for that Model class return _repositories[typeof (TEntity)] as IRepository; } // If the repository for that Model class doesn't exist, create it var repository = new Repository(_ctx); // Add it to the dictionary _repositories.Add(typeof (TEntity), repository); return repository; } public void Save() { // save all changes together _ctx.SaveChanges(); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (!_disposed) { if (disposing) { _ctx.Dispose(); } _disposed = true; } } } 

服务


 public interface IService { IList GetUserDetails(int userId); } 

 public class Service : IService { private readonly IRepository _userRepository; public Service (IUnitOfWork unitOfWork) { _unitOfWork = unitOfWork; _userRepository=_unitOfWork.GetRepository(); } public IList GetUserDetails(int userId) { return _userRepository.GetAll(); } } 

调节器


  public class HomeController // use the same patter which has been used in service { private readonly IService _service; public HomeController(IService service) { _service=service; } public ActionResult Index() { return _service. GetUserDetails(/*userid*/); } 

}


希望这段代码能够帮助很多用户和你。

在我们开始之前,将合同的概念与层分开可能是有意义的。 您列出了4个图层,但也可以将它们描述为3个图层和一个合约架构(域合同架构),它是交叉剪切,包含对DAL,BL和可能更高级别层的关注。

  1. 域:JUST域类
  2. DAL:负责访问数据,包含UOW和存储库以及与数据访问相关的validation。
  3. BL:独特负责业务逻辑和DAL的独特老板。
  4. UI:这不是那么重要! (即使它可能是一个控制台应用程序!)

关于典型的LOB样式的SOA n层体系结构,其中服务可能被其他团队或客户使用,一般来说,争取三个以上的契约模式可能是有意义的。

第一个是消费者与您希望提供的服务之间的合同模式。 这些可能是版本的。 这些模式可以是特定于用例的,并且以各种forms的规范化和组合提供基础实体模式的“表示”。 这些模式甚至可以包括支持元数据以支持特定于用例的需求,例如查找列表的数量和指示特定于用例的用户权限。

第二个是所有当前实现都在运行的实体域模式。 这始终是最新的,并且表示面向对象设计方式的逻辑模式。

第三个是数据所在的物理模式。 这始终是最新的,并且以存储技术所要求的任何适当的设计方式包含您的数据,无论是以关系设计方式还是其他方式。 请注意,虽然物理模式和逻辑模式通常看起来相似甚至相同,但有时在物理存储技术中存在可能要求物理模式不同的限制。 例如,MS Sql Server表中每行不应超过8060个字节,并且在某些情况下,如果使用MS Sql Server,则单个逻辑实体数据对象可以存储在多个一对一相关物理表中。

考虑到这三种模式,您可以构建解决方案以解决支持这些模式的问题。

要解决物理模式的存储和管理,请选择存储技术/策略(即:Sql Server,Oracle,MySql,xml,MongoDb等)

要解决物理模式的I / O并从物理模式转换为实体模式,需要引入IDataAccess图层接口。

要解决必须始终围绕实体或实体集强制执行的业务规则,无论用例如何,都要引入IBusiness层接口。

要解决特定于用例的规则,您不希望在多个客户端之间重复并在实体模式和服务合同模式之间进行转换,请引入IApplicationService层接口。

要解决外部公开服务及其合同模式传输对象的问题,请引入相应的主机控制器类( ApplicationService Controller, ApplicationService WCFHost或ApplicationService .asmx等)。

以下是通用命名空间策略中包含的一组接口,您可以实现这些接口,为您提供实体架构以及数据访问和业务层的抽象。

AcmeFrameworkContracts.dll

 public class Response {} public class Response : Response where TResponse : Response {} 

AcmeFramework.dll

参考: AcmeFrameworkContracts.dll

 namespace AcmeFramework { namespace Entity { public abstract class Entity where TEntity : Entity where TDataObject : Entity.BaseDataObject where TDataObjectList : Entity.BaseDataObjectList, new() where TIBusiness : Entity.IBaseBusiness where TIDataAccess : Entity.IBaseDataAccess where TPrimaryKey : IComparable, IEquatable { public class BaseDataObject { public TPrimaryKey Id; } public class BaseDataObjectList : CollectionBase { public TDataObjectList ShallowClone() { ... } } public interface IBaseBusiness { TDataObjectList LoadAll(); TDataObject LoadById(TPrimaryKey id); TDataObject LoadByIds(IEnumerable ids); IQueryable Query(); IQueryable FindBy(Expression> predicate); void Delete(TPrimaryKey ids); void Delete(IEnumerable ids); void Save(TDataObject entity); void Save(TDataObjectList entities); ValidationErrors Validate(TDataObject entity); // <- Define ValidationErrors as you see fit ValidationErrors Validate(TDataObjectList entities); // <- Define ValidationErrors as you see fit } public abstract BaseBusiness : IBaseBusiness { private TIDataAccess dataAccess; protected BaseBusiness(TIDataAccess dataAccess) { this.dataAccess = dataAccess; } } public interface IBaseDataAccess { IQueryable Query(); IQueryable FindBy(Expression> predicate); void DeleteBy(Expression> predicate); void Save(TDataObjectList entities); } } } namespace Application { public interface IBaseApplicationService {} public class BaseApplicationServiceWebAPIHost : ApiController where TIApplicationService : IBaseApplicationService { private TIApplicationService applicationService; public BaseApplicationServiceWebAPIHost(TIApplicationService applicationService) { this.applicationService = applicationService; } } public class BaseApplicationServiceWCFHost where TIApplicationService : IBaseApplicationService { private TIApplicationService applicationService; public BaseApplicationServiceWCFHost(TIApplicationService applicationService) { this.applicationService = applicationService; } } } 

像这样使用它:

UserDomain.dll

参考: AcmeFramework.dll

 namespace UserDomain { public class User : Entity { public class DataObject : BaseDataObject { public string FirstName; public string LastName; public bool IsActive { get; } } public class DataObjectList : BaseDataObjectList {} public interface IBusiness : IBaseBusiness { void DeactivateUser(Guid userId); } public interface IDataAccess : IBaseDataAccess {} public class Business { public Business(User.IDataAccess dataAccess) : base(dataAccess) {} public void DeactivateUser(Guid userId) { ... } } } public class UserPermission : Entity { public class DataObject : BaseDataObject { public Guid PermissionId; public Guid UserId; } public class DataObjectList : BaseDataObjectList {} public interface IBusiness : IBaseBusiness {} public interface IDataAccess : IBaseDataAccess {} public class Business { public Business(UserPermission.IDataAccess dataAccess) : base(dataAccess) {} } } public class Permission : Entity { public class DataObject : BaseDataObject { public string Code; public string Description; } public class DataObjectList : BaseDataObjectList {} public interface IBusiness : IBaseBusiness {} public interface IDataAccess : IBaseDataAccess {} public class Business { public Business(Permission.IDataAccess dataAccess) : base(dataAccess) {} } } } 

UserManagementApplicationContracts.dll

参考: AcmeFrameworkContracts.dll

 namespace UserManagement.Contracts { public class ReviewUserResponse : Response { public class UserPermission { public Guid id; public string permission; // <- formatted as "permissionCode [permissionDescription]" } public class User { public Guid id; public string firstName; public string lastName; public List permissions; } public User user; } public class EditUserResponse : Response { public class Permission { public Guid id; public string permissionCode; public string description; } public class UserPermission { public Guid id; public Guid permissionId; } public class User { public Guid id; public string firstName; public string lastName; public List permissions; } public List knownPermissions; public User user; } public interface IUserManagementApplicationService : IBaseApplicationService { Response EditUser(Guid userId); Response SaveUser(EditUserResponse.user user); Response ViewUser(Guid userId); } } 

UserManagementApplicationImplementation.dll

参考: AcmeFramework.dllAcmeFrameworkContracts.dllUserManagementApplicationContracts.dllUserDomain.dll

 namespace UserManagement.Implementation { public class UserManagementApplicationService : IUserManagementApplicationService { private User.IBusiness userBusiness; private UserPermissions.IBusiness userPermissionsBusiness; private Permission.IBusiness permissionBusiness; public UserManagementApplicationService(User.IBusiness userBusiness, UserPermission.IBusiness userPermissionsBusiness, Permission.IBusiness permissionBusiness) { this.userBusiness = userBusiness; this.userPermissionsBusiness = userPermissionsBusiness; this.permissionBusiness = permissionBusiness; } public Response EditUser(Guid userId) { ... } public Response SaveUser(EditUserResponse.user user) { ... } public Response ViewUser(Guid userId) { ... } } } 

如果您愿意,可以在UOW中进行分层。 您还可以根据需要公开更具逻辑实体特定的服务和主机,而不是特定于用例,但请记住不要将域架构类放在合同库中。 这样,您可以独立于底层实现来发展合同。 您可以将Entity子类移动到域合同库(如UserDomain.Contracts.dll),如果您希望隔离,则将实现保留在域库(如UserDomain.dll)中。