在将业务层与数据层分离时,对实体施加限制的位置 [英] Where to put restrictions on entities when separating Business layer from Data Layer

查看:178
本文介绍了在将业务层与数据层分离时,对实体施加限制的位置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试为我的大型ASP.NET MVC应用程序创建业务和数据层。因为这是我第一次尝试这种规模的项目,所以我正在阅读一些书籍,并在妥善分类时要格外小心。通常,我的应用程序将业务逻辑和数据访问层混合在一起,并且多个业务实体在一个类中交织在一起(当我试图弄清楚在哪里添加东西时,这使我感到困惑)。



我一直在阅读的大部分内容是将业务和数据层分开。这似乎很好,但在某些情况下我很难准确地看到如何执行此操作。例如,假设我正在创建一个允许管理员向系统添加新产品的系统:

 公共类Product 
{
public ind Id {get;私人套装; }
公共字符串Name {get;组; }
公众十进制价格{组; }
}

然后我通过创建存储库来分离数据访问

 公共类ProductRepository 
{
public bool Add(Product product);
}

假设我要要求产品名称至少包含4个字符。我看不出如何做到这一点。



我的一个想法是扩展Name的set属性,并且仅在其长度为4个字符的情况下进行设置。但是,除了创建的Product.Name!=传入的名称外,没有其他方法可以使创建产品的方法知道名称。



我的另一个想法是将其放入存储库中的Add()方法中,但是然后我的数据逻辑就在那里存在我的业务逻辑,这也意味着Add调用是否失败,我不知道它是否失败了。业务逻辑或DAL失败(这也意味着我无法使用模拟框架对其进行测试)。



我唯一能想到的就是将DAL内容放入从存储库中的Add()方法调用的第三层中,但我没有在我的书或网上的任何领域建模示例中都可以看到(至少我已经看过)。当我不确定是否需要时,它还会增加域模型的复杂性。



另一个示例是要确保名称仅由一种产品使用。



作为补充说明,我打算将NHibernate用作我的ORM,以完成什么工作?



我希望它(理论上)与我使用的ORM无关,因为TDD应该能够将其全部隔离。



请先感谢!

解决方案

我通常通过使用分层体系结构来解决此问题。这个怎么做?您基本上有以下(理想情况下)的VS项目:




  • 表示层(UI内容所在的位置)

  • 业务层(实际业务逻辑所在的位置)

  • 数据访问层(您与基础DBMS进行通信的位置)



为了将所有这些都去耦,我使用了所谓的接口层st最后,我有




  • 表示层(UI
    的东西所在的位置)

  • IBusiness层(包含
    业务层的接口)

  • 业务层(实际业务逻辑所在的
    所在的地方)

  • IDataAccess层(包含DAO层的
    接口)

  • 数据访问层(在其中与基础DBMS通信



这非常方便,并且创建了一个很好的解耦架构。基本上,您的表示层只访问接口,而不访问实现本身。为了创建相应的实例,您应该使用Factory或最好是一些依赖项注入库( Unity 很适合。网络应用程序或Spring.Net。)



这如何影响您的应用程序的业务逻辑/可测试性?

详细介绍所有内容可能已经太久了,但是如果您担心具有可测试的设计,则应该绝对考虑依赖注入库。



使用NHibernate,...无论使用什么ORM

DAO层都通过接口与其他层完全隔离,您可以使用任何背后的技术来访问基础数据库。您可以根据需要直接发出SQL查询或使用NHibernate。令人高兴的是,它与应用程序的其余部分完全独立。您可以从今天开始手动编写SQL,明天就可以与使用NHibernate的DAO dll交换,而无需在BL或表示层中进行任何更改。

而且测试BL逻辑很简单。您可能有一个类似的类:

 公共类ProductsBl:IProductsBL 
{

/ /这由某些框架注入
public IProductsDao ProductsDao {get;组; }

public void SaveProduct(产品产品)
{
//对产品对象进行验证并做出适当的反应
...

//如果有效,则持续下去
ProductsDao.PersistProduct(product);
}

...
}

现在,您可以通过在测试用例中模拟ProductDao来轻松地在 SaveProduct(...)方法中测试验证逻辑。


I am attempting to create the the business and data layers for my big ASP.NET MVC application. As this is the first time for me attempting a project of this scale I am reading some books and trying to take good care at separating things out properly. Usually my applications mix the business logic and data access layers, and multiple business entities are intertwined in the single class (which has confused me a few times when I was trying to figure out where to add things).

Most of what I have been reading is to separate out the business and data layers. This seems all fine and dandy, but I am having trouble visualizing exactly how to do this in some scenarios. For example, let's say I am creating a system that allows admins to add a new product to the system:

public class Product
{ 
   public int Id { get; private set; }
   public string Name { get; set; }
   public decimal Price { get; set; }
}

Then I separate out the data access by creating a repository

public class ProductRepository
{
   public bool Add(Product product);
}

Let's say I want to require a product's name to have at least 4 characters. I can't see how to do this cleanly.

One idea I had was to expand the Name's set property and only set it if it's 4 characters long. However, there is no way for a method that is creating the product to know the name didn't get set except that Product.Name != whatever they passed in.

Another idea I had is to put it in the Add() method in the repository, but then I have my business logic right there with the data logic, which also means if the Add call fails I don't know if it failed for the business logic or because the DAL failed (and it also means I can't test it using mock frameworks).

The only thing I can think of is to put my DAL stuff in a 3rd layer that gets called from the Add() method in the repository, but I don't see this in any of the domain modelling examples in my book or on the web (that I've seen at least). It also adds to the complexity of the domain models when I am not sure it is needed.

Another example is wanting to make sure that a Name is only used by one product. Would this go in the Product class, ProductRepository Add() method, or where?

As a side note, I plan to use NHibernate as my ORM however, to accomplish what I want it (theoretically) shouldn't matter what ORM I am using since TDD should be able to isolate it all.

Thanks in advance!

解决方案

I usually approach this by using a layered architecture. How to do this? You basically have the following (ideally) VS projects:

  • Presentation layer (where the UI stuff resides)
  • Business layer (where the actual business logic resides)
  • Data access layer (where you communicate with your underlying DBMS)

For decoupling all of them I use so-called interface layers s.t. in the end I have

  • Presentation layer (where the UI stuff resides)
  • IBusiness layer (containing the interfaces for the business layer)
  • Business layer (where the actual business logic resides)
  • IDataAccess layer (containing the interfaces for the DAO layer)
  • Data access layer (where you communicate with your underlying DBMS)

This is extremely handy and creates a nicely decoupled architecture. Basically your presentation layer just accesses the interfaces and not the implementations itself. For creating the according instances you should use a Factory or preferably some dependency injection library (Unity is good for .Net apps or alternatively Spring.Net).

How does this impact on your business logic / testability of your app?
It is probably too long to write everything in detail, but if you're concerned about having a well testable design you should absolutely consider dependency injection libraries.

Using NHibernate,...whatever ORM
Having a DAO layer completely separated through the interfaces from the other layers you can use whatever technology behind for accessing your underlying DB. You could directly issue SQL queries or use NHibernate, as you wish. The nice thing is that it is totally independent from the rest of your app. You could event start today by writing SQLs manually and tomorrow exchange your DAO dll with one that uses NHibernate without a single change in your BL or presentation layer.
Moreover testing your BL logic is simple. You may have a class like:

public class ProductsBl : IProductsBL
{

   //this gets injected by some framework
   public IProductsDao ProductsDao { get; set; }

   public void SaveProduct(Product product)
   {
      //do validation against the product object and react appropriately
      ...

      //persist it down if valid
      ProductsDao.PersistProduct(product);
   }

   ...
}

Now you can easily test the validation logic in your SaveProduct(...) method by mocking out the ProductDao in your test case.

这篇关于在将业务层与数据层分离时,对实体施加限制的位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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