I have created a POCO model class and a repository class which handles persistence. Since the POCO cannot access the repository, there are lots of business logic tasks in the repository which doesn't seem right. From what I have read, it looks like I need a service layer that sits between the UI consumers and the repository layer. What I am not sure of is exactly how it is supposed to work...
我创建了一个POCO模型类和一个处理持久性的存储库类。由于POCO不能访问存储库,所以存储库中有许多业务逻辑任务看起来不正确。根据我所读到的,看起来我需要一个位于UI消费者和存储库层之间的服务层。我不确定的是它应该如何工作……
In addition to the service layer, should there also be a separate business logic layer, or is that the role of the service layer?
除了服务层之外,还应该有一个独立的业务逻辑层,还是服务层的角色?
Should there be one service per repository?
每个存储库应该有一个服务吗?
Is the service layer the only way that the UI can instance the model objects or does the repository provide the new model instance to the service?
服务层是UI实例化模型对象的唯一方式,还是存储库向服务提供新的模型实例?
Do I put my parameter, model and other validations in the service layer that do things like check to make sure a input is valid and that a item to update exists in the database before updating?
是否将参数、模型和其他验证放在服务层中,以确保输入是有效的,并且在更新之前数据库中存在要更新的项?
Can the model, repository and UI all make calls to the service layer, or is it just for the UI to consume?
模型、存储库和UI都可以对服务层进行调用,还是只对UI进行消费?
Is the service layer supposed to be all static methods?
服务层应该是所有的静态方法吗?
What would be a typical way to call the service layer from the UI?
从UI调用服务层的典型方法是什么?
What validations should be on the model vs the service layer?
模型对服务层的验证应该是什么?
Here is some sample code for my existing layers:
下面是我现有图层的一些示例代码:
public class GiftCertificateModel
{
public int GiftCerticiateId {get;set;}
public string Code {get;set;}
public decimal Amount {get;set;}
public DateTime ExpirationDate {get;set;}
public bool IsValidCode(){}
}
public class GiftCertificateRepository
{
//only way to access database
public GiftCertificateModel GetById(int GiftCertificateId) { }
public List<GiftCertificateModel> GetMany() { }
public void Save(GiftCertificateModel gc) { }
public string GetNewUniqueCode() { //code has to be checked in db }
public GiftCertificateModel CreateNew()
{
GiftCertificateModel gc = new GiftCertificateModel();
gc.Code = GetNewUniqueCode();
return gc;
}
}
UPDATE: I am currently using web forms and classic ADO.NET. I hope to move to MVC and EF4 eventually.
更新:我目前使用的是web表单和经典的ADO.NET。我希望最终能转移到MVC和EF4。
UPDATE: Big thanks to @Lester for his great explanation. I now understand that I need to add a service layer for each of my repositories. This layer will be the ONLY way the UI or other services can communicate with the repository and will contain any validations that do not fit on the domain object (eg - validations that need to call the repo)
更新:非常感谢@Lester的精彩解释。现在我明白我需要为我的每个存储库添加一个服务层。这个层将是UI或其他服务与存储库通信的唯一方式,并且将包含不适合域对象的任何验证(例如,需要调用repo的验证)
public class GiftCertificateService()
{
public void Redeem(string code, decimal amount)
{
GiftCertificate gc = new GiftCertificate();
if (!gc.IsValidCode(code))
{
throw new ArgumentException("Invalid code");
}
if (amount <= 0 || GetRemainingBalance(code) < amount)
{
throw new ArgumentException("Invalid amount");
}
GiftCertificateRepository gcRepo = new GiftCertificateRepository();
gcRepo.Redeem(code, amount);
}
public decimal GetRemainingBalance(string code)
{
GiftCertificate gc = new GiftCertificate();
if (!gc.IsValidCode(code))
{
throw new ArgumentException("Invalid code");
}
GiftCertificateRepository gcRepo = new GiftCertificateRepository();
gcRepo.GetRemainingBalance(code);
}
public SaveNewGC(GiftCertificate gc)
{
//validates the gc and calls the repo save method
//updates the objects new db ID
}
}
Questions
问题
-
Do I add the same (and possibly more) properties to the service as I have on my model (amount, code, etc) or do I only offer methods that accept GiftCertificate objects and direct parameters?
我是像我的模型(数量、代码等)一样向服务添加相同(甚至可能更多)的属性,还是只提供接受GiftCertificate对象和直接参数的方法?
-
Do I create a default instance of the GiftCertificate entity when the Service constructor is called or just create new ones as needed (eg - for validation methods in the service that need to call validation methods in the entity? Also, same question about creating a default repository instance...?
我是在调用服务构造函数时创建GiftCertificate实体的默认实例,还是在需要时创建新的实例(例如,对于需要调用实体中的验证方法的服务中的验证方法)?同样,关于创建默认存储库实例的问题…?
-
I know i expose the functionality of the repo via the service, do I also expose the methods from the entity as well (eg - IsValidCode, etc)?
我知道我通过服务公开了repo的功能,我是否也公开了来自实体的方法(例如- IsValidCode等)?
-
It is ok for the UI to simply create a new GiftCertificate object directly without going through the service (eg - to call parameter validation methods from the entity). If not, how to enforce it?
UI可以直接创建一个新的GiftCertificate对象,而无需通过服务(例如,从实体调用参数验证方法)。如果没有,如何执行?
-
On the UI layer, when I want to create a new gift certificate, do I call the model/service validations (like IsValidExpirationDate, etc) directly from the UI layer OR do I hydrate the object first, then pass it in to be validated and then return some sort of validation summary back to the UI?
UI层,当我想要创建一个新的礼券,我调用模型/服务验证(IsValidExpirationDate等)直接从UI层或我首先水合物对象,然后通过在进行验证,然后返回某种验证总结UI ?
Also, if I want to Redeem from the UI layer, do I first call the model/service validation methods from the UI to give user feedback and then call the Redeem method which will run the same checks again internally?
此外,如果我想从UI层进行赎回,我是否首先调用UI中的模型/服务验证方法来给用户反馈,然后调用赎回方法,该方法将在内部再次运行相同的检查?
Example for calling service to do a Redeem operation from UI:
调用服务从UI执行赎回操作的示例:
string redeemCode = RedeemCodeTextBox.Text;
GiftCertificateService gcService = new GiftCertificateService();
GiftCertificate gc = new GiftCertificate(); //do this to call validation methods (should be through service somehow?)
if (!gc.IsValid(redeemCode))
{
//give error back to user
}
if (gcService.GetRemainingBalance(redeemCode) < amount)
{
//give error back to user
}
//if no errors
gcService.Redeem(code,amount);
Example for creating a new Gift certificate from UI:
从用户界面创建新礼品证书的例子:
GiftCertificateService gcService = new GiftCertificateService();
GiftCertificate gc = new GiftCertificate();
if (!gc.IsValidExpDate(inputExpDate))
{
//give error to user..
}
//if no errors...
gc.Code = gcService.GetNewCode();
gc.Amount = 10M;
gc.ExpirationDate = inputExpDate;
gcService.SaveNewGC(gc);
//method updates the gc with the new id...
Something feels wrong about way GCs are being created and how the validations are separated between entity/service. The user/consumer should not have to be concerned with what validations are in which place... advice?
在创建GCs的过程中出现了一些错误,以及在实体/服务之间如何区分验证。用户/消费者不应该关心在什么地方有什么验证。建议吗?
3 个解决方案
#1
40
Take a look at S#arp Architeture . It's like a best practices architectural framework for building ASP.NET MVC applications. The general architecture pattern is to have 1 repository per entity which is responsible only for data access and 1 service per repository which is responsible only for business logic and communicating between controllers and services.
看看s# arp架构设计。这就像是构建ASP的最佳实践架构框架。净MVC应用程序。一般的体系结构模式是每个实体有一个存储库,该存储库只负责数据访问,每个存储库有一个服务,该服务只负责业务逻辑和控制器和服务之间的通信。
To answer your questions based on S#arp Architeture:
根据s# arp架构来回答您的问题:
In addition to the service layer, should there also be a separate business logic layer, or is that the role of the service layer?
除了服务层之外,还应该有一个独立的业务逻辑层,还是服务层的角色?
Models should be responsible for field-level validation (ex. using required field attributes) while controllers can validate data before saving (ex. checking state before saving).
模型应该负责字段级验证(例如,使用必需的字段属性),而控制器可以在保存之前验证数据(例如,保存前检查状态)。
Should there be one service layer per repository?
每个存储库应该有一个服务层吗?
Yes - there should be one service per repository (not 1 service layer per repository but I'm guessing you meant that).
是的——每个存储库应该有一个服务(不是每个存储库有一个服务层,但我猜您是这个意思)。
Is the service layer the only way that the UI can instance the model objects or does the repository provide the new model instance to the service?
服务层是UI实例化模型对象的唯一方式,还是存储库向服务提供新的模型实例?
Repositories and services can return a single entity, a collection of entities, or data transfer objects (DTOs) as required. Controllers will pass these values to a static constructor method in the model which will return an instance of the model.
存储库和服务可以根据需要返回单个实体、实体集合或数据传输对象(dto)。控制器将这些值传递给模型中的静态构造函数方法,该方法将返回模型的实例。
ex Using DTOs:
使用dto交货:
GiftCertificateModel.CreateGiftCertificate(int GiftCerticiateId, string Code, decimal Amount, DateTime ExpirationDate)
Do I put my parameter, model and other validations in the service layer that do things like check to make sure a input is valid and that a item to update exists in the database before updating?
是否将参数、模型和其他验证放在服务层中,以确保输入是有效的,并且在更新之前数据库中存在要更新的项?
Models validate field-level values ex. making sure input is valid by checking for required fields, age or date ranges, etc. Services should do any validation needed that requires checking outside of the model value ex. Checking that the gift certificate hasn't been redeemed yet, checking properties of the store the gift certificate is for).
模型验证字段级仓库确保输入值是有效的为必填字段,通过检查年龄或日期范围,等。服务应该做任何验证模型的需要,需要检查外例检查礼券价值尚未赎回,检查商店的礼券的属性)。
Can the model, repository and UI all make calls to the service layer, or is it just for the UI to consume?
模型、存储库和UI都可以对服务层进行调用,还是只对UI进行消费?
Controllers and other services should be the only ones making calls to the service layer. Services should be the only one makes making calls to repositories.
控制器和其他服务应该是唯一调用服务层的。服务应该是唯一调用存储库的服务。
Is the service layer supposed to be all static methods?
服务层应该是所有的静态方法吗?
They can be but it's easier to maintain and extend if they aren't. Changes to entities and adding/removing subclasses are easier to change if there's 1 service per entity / subclass.
它们可以是,但如果不是,则更容易维护和扩展。如果每个实体/子类有一个服务,那么对实体的更改和添加/删除子类就更容易更改。
What would be a typical way to call the service layer from the UI?
从UI调用服务层的典型方法是什么?
Some examples of controllers calling the service layer:
一些控制器调用服务层的例子:
giftCertificateService.GetEntity(giftCertificateId); (which in turn is just a call to the giftCertificateRepository.GetEntity(giftCertificateId)
giftCertificateService.Redeem(giftCertificate);
What validations should be on the model vs the service layer?
模型对服务层的验证应该是什么?
Already answered above.
上面已经回答了。
UPDATE
更新
Since you're using WebForms it may be a little harder to grasp some of the concepts but everything I've mentioned is applicable since what I'm describing is a general MVC paradigm. ADO.NET for data access doesn't matter since data access is decoupled via repositories.
由于您正在使用WebForms,所以理解其中的一些概念可能有点困难,但是我所提到的一切都是适用的,因为我所描述的是一个通用的MVC范型。ADO。NET的数据访问无关紧要,因为数据访问是通过存储库解耦的。
Do I add the same (and possibly more) properties to the service as I have on my model (amount, code, etc) or do I only offer methods that accept GiftCertificate objects and direct parameters?
我是像我的模型(数量、代码等)一样向服务添加相同(甚至可能更多)的属性,还是只提供接受GiftCertificate对象和直接参数的方法?
You need to look at the services as exactly what their name implies - actions that controllers can invoke. You won't need properties that are defined in your model since they are already available in the model.
您需要确切地了解服务的名称——控制器可以调用的操作。您不需要在模型中定义的属性,因为它们已经在模型中可用。
Do I create a default instance of the GiftCertificate entity when the Service constructor is called or just create new ones as needed (eg - for validation methods in the service that need to call validation methods in the entity? Also, same question about creating a default repository instance...?
我是在调用服务构造函数时创建GiftCertificate实体的默认实例,还是在需要时创建新的实例(例如,对于需要调用实体中的验证方法的服务中的验证方法)?同样,关于创建默认存储库实例的问题…?
Controllers and services should have private fields for services and repositories respectively. You shouldn't be instantiating for every action / method.
控制器和服务应该分别为服务和存储库拥有私有字段。不应该为每个操作/方法实例化。
I know i expose the functionality of the repo via the service, do I also expose the methods from the entity as well (eg - IsValidCode, etc)?
我知道我通过服务公开了repo的功能,我是否也公开了来自实体的方法(例如- IsValidCode等)?
Not too sure what you mean here. If services return entities then those methods on the entities are already exposed. If they return DTOs then that implies you're interested only in certain information.
我不太明白你的意思。如果服务返回实体,那么实体上的那些方法就已经公开了。如果他们返回dto,那意味着你只对某些信息感兴趣。
For validation I can see why you're a bit concerned since there's validation done directly on the model and other types of validation done in services. The rule of thumb I've used is that if validation requires calls to the db then it should be done in the service layer.
对于验证,我可以理解为什么您有点担心,因为直接在模型上执行验证,而在服务中执行其他类型的验证。我使用的经验法则是,如果验证需要调用db,那么应该在服务层中执行。
It is ok for the UI to simply create a new GiftCertificate object directly without going through the service (eg - to call parameter validation methods from the entity). If not, how to enforce it?
UI可以直接创建一个新的GiftCertificate对象,而无需通过服务(例如,从实体调用参数验证方法)。如果没有,如何执行?
On the UI layer, when I want to create a new gift certificate, do I call the model/service validations (like IsValidExpirationDate, etc) directly from the UI layer OR do I hydrate the object first, then pass it in to be validated and then return some sort of validation summary back to the UI?
UI层,当我想要创建一个新的礼券,我调用模型/服务验证(IsValidExpirationDate等)直接从UI层或我首先水合物对象,然后通过在进行验证,然后返回某种验证总结UI ?
For these 2 questions lets go through a scenario:
对于这两个问题,我们来看一个场景:
User enters information to create a new certificate and submits. There is field level validation so if a textbox is null or if the dollar amount is negative it throws a validation error. Assuming all fields are valid the controller will call the service gcService.Save(gc)
.
用户输入信息创建新证书并提交。有字段级验证,所以如果一个文本框是空的,或者如果美元数量是负数,它会抛出一个验证错误。假设所有字段都是有效的,控制器将调用服务gcService.Save(gc)。
The service will check other business logic, such as if the store already has issued too many gift certificates. It either returns an enum for the status if there are multiple error codes or throws an exception with the error information.
该服务将检查其他业务逻辑,比如商店已经颁发了太多的礼券。如果有多个错误代码,它要么返回状态的enum,要么抛出带有错误信息的异常。
Finally, the service calls gcRepository.Save(gc)
.
最后,服务调用gcRepository.Save(gc)。
#2
3
-
You don't have to create repository per entity,see here for more,
你不需要为每个实体创建存储库,更多信息请看这里,
Usually one defines a repository per aggregate in the domain. That is: we don't have a repository per entity! If we have a look at a simple order entry system the entity Order might be the root of a Order aggregate. Thus we will have an Order Repository.
通常在域中定义一个存储库。也就是说:我们没有每个实体的存储库!如果我们看一下简单的订单输入系统,实体订单可能是订单聚合的根。这样我们就有了一个订单存储库。
-
Should there be one service per repository? -> Not always, as you may use multiple repositories in one service.
每个存储库应该有一个服务吗?->并非总是如此,因为您可以在一个服务中使用多个存储库。
-
Service creates Model instance, repository will never interact to Model, in fact it returns the Entity which model will use subsequently.
服务创建模型实例,存储库永远不会与模型交互,实际上它返回模型随后使用的实体。
-
Handle Input/range etc kind of validation at UI level(u can use javascript or any other library), and let Services handle only business aspects. You can get the benefits of Attributes which will does the same.
在UI级别处理输入/范围等类型的验证(u可以使用javascript或任何其他库),并且让服务只处理业务方面。您可以得到属性的好处,它也会起到同样的作用。
-
UI->Service->Repository, if repository is calling service than thr must be something wrong IMO.
用户界面->服务->储存库,如果储存库调用的服务超过thr,那么在我看来一定是出了问题。
You code changes,
你代码更改,
-
Make Model and Repositories separate.
将模型和存储库分开。
public class GiftCertificateModel { } public class GiftCertificateRepository { //Remove Model related code from here, and just put ONLY database specific code here, (no business logic also). Common methods would be Get, GetById, Insert, Update etc. Since essence of Repository is to have common CRUD logic at one place soyou don't have to write entity specific code. You will create entity specific repository in rare cases, also by deriving base repository. } public class GiftCertificateService() { //Create Model instance here // Use repository to fill the model (Mapper) }
#3
0
You can create a service called GiftCertificateService.
您可以创建一个名为GiftCertificateService的服务。
That way you will coordinate any task that does not belong to the responsibility of the GiftCertificateModel into it's service. (Not to be confused with a WCF service).
这样,您将协调任何不属于GiftCertificateModel职责的任务到它的服务中。(不要与WCF服务混淆)。
The service will control all the tasks so your UI (or whatever caller that might be) will use the methods defined in the service.
服务将控制所有的任务,因此UI(或任何可能的调用者)将使用服务中定义的方法。
The service will then call methods on the model, use the repository, create transactions, etc.
然后,服务将调用模型上的方法,使用存储库,创建事务,等等。
For ex. (based on the sample code you provided):
(基于你提供的样本代码):
public class GiftCertificateService
{
public void CreateCertificate()
{
//Do whatever needs to create a certificate.
GiftCertificateRepository gcRepo = new GiftCertificateRepository();
GiftCertificateModel gc = gcRepo.CreateNew();
gc.Amount = 10.00M;
gc.ExpirationDate = DateTime.Today.AddMonths(12);
gc.Notes = "Test GC";
gcRepo.Save(gc);
}
}
The UI will call the CreateCertificate method (passing arguments, etc) and the method may return something also.
UI将调用CreateCertificate方法(传递参数等),该方法也可能返回一些东西。
NOTE: If you want the class to act on the UI though then create a controller class (if you are doing MVC) or a presenter class (if you are doing MVVM, and don't want to put everything inside the ViewModel) and use the GiftCertificateService from that class.
注意:如果您希望该类在UI上操作,然后创建一个控制器类(如果您正在做MVC)或一个presenter类(如果您正在做MVVM,并且不想把所有东西都放到ViewModel中),并使用该类的gift证书。
#1
40
Take a look at S#arp Architeture . It's like a best practices architectural framework for building ASP.NET MVC applications. The general architecture pattern is to have 1 repository per entity which is responsible only for data access and 1 service per repository which is responsible only for business logic and communicating between controllers and services.
看看s# arp架构设计。这就像是构建ASP的最佳实践架构框架。净MVC应用程序。一般的体系结构模式是每个实体有一个存储库,该存储库只负责数据访问,每个存储库有一个服务,该服务只负责业务逻辑和控制器和服务之间的通信。
To answer your questions based on S#arp Architeture:
根据s# arp架构来回答您的问题:
In addition to the service layer, should there also be a separate business logic layer, or is that the role of the service layer?
除了服务层之外,还应该有一个独立的业务逻辑层,还是服务层的角色?
Models should be responsible for field-level validation (ex. using required field attributes) while controllers can validate data before saving (ex. checking state before saving).
模型应该负责字段级验证(例如,使用必需的字段属性),而控制器可以在保存之前验证数据(例如,保存前检查状态)。
Should there be one service layer per repository?
每个存储库应该有一个服务层吗?
Yes - there should be one service per repository (not 1 service layer per repository but I'm guessing you meant that).
是的——每个存储库应该有一个服务(不是每个存储库有一个服务层,但我猜您是这个意思)。
Is the service layer the only way that the UI can instance the model objects or does the repository provide the new model instance to the service?
服务层是UI实例化模型对象的唯一方式,还是存储库向服务提供新的模型实例?
Repositories and services can return a single entity, a collection of entities, or data transfer objects (DTOs) as required. Controllers will pass these values to a static constructor method in the model which will return an instance of the model.
存储库和服务可以根据需要返回单个实体、实体集合或数据传输对象(dto)。控制器将这些值传递给模型中的静态构造函数方法,该方法将返回模型的实例。
ex Using DTOs:
使用dto交货:
GiftCertificateModel.CreateGiftCertificate(int GiftCerticiateId, string Code, decimal Amount, DateTime ExpirationDate)
Do I put my parameter, model and other validations in the service layer that do things like check to make sure a input is valid and that a item to update exists in the database before updating?
是否将参数、模型和其他验证放在服务层中,以确保输入是有效的,并且在更新之前数据库中存在要更新的项?
Models validate field-level values ex. making sure input is valid by checking for required fields, age or date ranges, etc. Services should do any validation needed that requires checking outside of the model value ex. Checking that the gift certificate hasn't been redeemed yet, checking properties of the store the gift certificate is for).
模型验证字段级仓库确保输入值是有效的为必填字段,通过检查年龄或日期范围,等。服务应该做任何验证模型的需要,需要检查外例检查礼券价值尚未赎回,检查商店的礼券的属性)。
Can the model, repository and UI all make calls to the service layer, or is it just for the UI to consume?
模型、存储库和UI都可以对服务层进行调用,还是只对UI进行消费?
Controllers and other services should be the only ones making calls to the service layer. Services should be the only one makes making calls to repositories.
控制器和其他服务应该是唯一调用服务层的。服务应该是唯一调用存储库的服务。
Is the service layer supposed to be all static methods?
服务层应该是所有的静态方法吗?
They can be but it's easier to maintain and extend if they aren't. Changes to entities and adding/removing subclasses are easier to change if there's 1 service per entity / subclass.
它们可以是,但如果不是,则更容易维护和扩展。如果每个实体/子类有一个服务,那么对实体的更改和添加/删除子类就更容易更改。
What would be a typical way to call the service layer from the UI?
从UI调用服务层的典型方法是什么?
Some examples of controllers calling the service layer:
一些控制器调用服务层的例子:
giftCertificateService.GetEntity(giftCertificateId); (which in turn is just a call to the giftCertificateRepository.GetEntity(giftCertificateId)
giftCertificateService.Redeem(giftCertificate);
What validations should be on the model vs the service layer?
模型对服务层的验证应该是什么?
Already answered above.
上面已经回答了。
UPDATE
更新
Since you're using WebForms it may be a little harder to grasp some of the concepts but everything I've mentioned is applicable since what I'm describing is a general MVC paradigm. ADO.NET for data access doesn't matter since data access is decoupled via repositories.
由于您正在使用WebForms,所以理解其中的一些概念可能有点困难,但是我所提到的一切都是适用的,因为我所描述的是一个通用的MVC范型。ADO。NET的数据访问无关紧要,因为数据访问是通过存储库解耦的。
Do I add the same (and possibly more) properties to the service as I have on my model (amount, code, etc) or do I only offer methods that accept GiftCertificate objects and direct parameters?
我是像我的模型(数量、代码等)一样向服务添加相同(甚至可能更多)的属性,还是只提供接受GiftCertificate对象和直接参数的方法?
You need to look at the services as exactly what their name implies - actions that controllers can invoke. You won't need properties that are defined in your model since they are already available in the model.
您需要确切地了解服务的名称——控制器可以调用的操作。您不需要在模型中定义的属性,因为它们已经在模型中可用。
Do I create a default instance of the GiftCertificate entity when the Service constructor is called or just create new ones as needed (eg - for validation methods in the service that need to call validation methods in the entity? Also, same question about creating a default repository instance...?
我是在调用服务构造函数时创建GiftCertificate实体的默认实例,还是在需要时创建新的实例(例如,对于需要调用实体中的验证方法的服务中的验证方法)?同样,关于创建默认存储库实例的问题…?
Controllers and services should have private fields for services and repositories respectively. You shouldn't be instantiating for every action / method.
控制器和服务应该分别为服务和存储库拥有私有字段。不应该为每个操作/方法实例化。
I know i expose the functionality of the repo via the service, do I also expose the methods from the entity as well (eg - IsValidCode, etc)?
我知道我通过服务公开了repo的功能,我是否也公开了来自实体的方法(例如- IsValidCode等)?
Not too sure what you mean here. If services return entities then those methods on the entities are already exposed. If they return DTOs then that implies you're interested only in certain information.
我不太明白你的意思。如果服务返回实体,那么实体上的那些方法就已经公开了。如果他们返回dto,那意味着你只对某些信息感兴趣。
For validation I can see why you're a bit concerned since there's validation done directly on the model and other types of validation done in services. The rule of thumb I've used is that if validation requires calls to the db then it should be done in the service layer.
对于验证,我可以理解为什么您有点担心,因为直接在模型上执行验证,而在服务中执行其他类型的验证。我使用的经验法则是,如果验证需要调用db,那么应该在服务层中执行。
It is ok for the UI to simply create a new GiftCertificate object directly without going through the service (eg - to call parameter validation methods from the entity). If not, how to enforce it?
UI可以直接创建一个新的GiftCertificate对象,而无需通过服务(例如,从实体调用参数验证方法)。如果没有,如何执行?
On the UI layer, when I want to create a new gift certificate, do I call the model/service validations (like IsValidExpirationDate, etc) directly from the UI layer OR do I hydrate the object first, then pass it in to be validated and then return some sort of validation summary back to the UI?
UI层,当我想要创建一个新的礼券,我调用模型/服务验证(IsValidExpirationDate等)直接从UI层或我首先水合物对象,然后通过在进行验证,然后返回某种验证总结UI ?
For these 2 questions lets go through a scenario:
对于这两个问题,我们来看一个场景:
User enters information to create a new certificate and submits. There is field level validation so if a textbox is null or if the dollar amount is negative it throws a validation error. Assuming all fields are valid the controller will call the service gcService.Save(gc)
.
用户输入信息创建新证书并提交。有字段级验证,所以如果一个文本框是空的,或者如果美元数量是负数,它会抛出一个验证错误。假设所有字段都是有效的,控制器将调用服务gcService.Save(gc)。
The service will check other business logic, such as if the store already has issued too many gift certificates. It either returns an enum for the status if there are multiple error codes or throws an exception with the error information.
该服务将检查其他业务逻辑,比如商店已经颁发了太多的礼券。如果有多个错误代码,它要么返回状态的enum,要么抛出带有错误信息的异常。
Finally, the service calls gcRepository.Save(gc)
.
最后,服务调用gcRepository.Save(gc)。
#2
3
-
You don't have to create repository per entity,see here for more,
你不需要为每个实体创建存储库,更多信息请看这里,
Usually one defines a repository per aggregate in the domain. That is: we don't have a repository per entity! If we have a look at a simple order entry system the entity Order might be the root of a Order aggregate. Thus we will have an Order Repository.
通常在域中定义一个存储库。也就是说:我们没有每个实体的存储库!如果我们看一下简单的订单输入系统,实体订单可能是订单聚合的根。这样我们就有了一个订单存储库。
-
Should there be one service per repository? -> Not always, as you may use multiple repositories in one service.
每个存储库应该有一个服务吗?->并非总是如此,因为您可以在一个服务中使用多个存储库。
-
Service creates Model instance, repository will never interact to Model, in fact it returns the Entity which model will use subsequently.
服务创建模型实例,存储库永远不会与模型交互,实际上它返回模型随后使用的实体。
-
Handle Input/range etc kind of validation at UI level(u can use javascript or any other library), and let Services handle only business aspects. You can get the benefits of Attributes which will does the same.
在UI级别处理输入/范围等类型的验证(u可以使用javascript或任何其他库),并且让服务只处理业务方面。您可以得到属性的好处,它也会起到同样的作用。
-
UI->Service->Repository, if repository is calling service than thr must be something wrong IMO.
用户界面->服务->储存库,如果储存库调用的服务超过thr,那么在我看来一定是出了问题。
You code changes,
你代码更改,
-
Make Model and Repositories separate.
将模型和存储库分开。
public class GiftCertificateModel { } public class GiftCertificateRepository { //Remove Model related code from here, and just put ONLY database specific code here, (no business logic also). Common methods would be Get, GetById, Insert, Update etc. Since essence of Repository is to have common CRUD logic at one place soyou don't have to write entity specific code. You will create entity specific repository in rare cases, also by deriving base repository. } public class GiftCertificateService() { //Create Model instance here // Use repository to fill the model (Mapper) }
#3
0
You can create a service called GiftCertificateService.
您可以创建一个名为GiftCertificateService的服务。
That way you will coordinate any task that does not belong to the responsibility of the GiftCertificateModel into it's service. (Not to be confused with a WCF service).
这样,您将协调任何不属于GiftCertificateModel职责的任务到它的服务中。(不要与WCF服务混淆)。
The service will control all the tasks so your UI (or whatever caller that might be) will use the methods defined in the service.
服务将控制所有的任务,因此UI(或任何可能的调用者)将使用服务中定义的方法。
The service will then call methods on the model, use the repository, create transactions, etc.
然后,服务将调用模型上的方法,使用存储库,创建事务,等等。
For ex. (based on the sample code you provided):
(基于你提供的样本代码):
public class GiftCertificateService
{
public void CreateCertificate()
{
//Do whatever needs to create a certificate.
GiftCertificateRepository gcRepo = new GiftCertificateRepository();
GiftCertificateModel gc = gcRepo.CreateNew();
gc.Amount = 10.00M;
gc.ExpirationDate = DateTime.Today.AddMonths(12);
gc.Notes = "Test GC";
gcRepo.Save(gc);
}
}
The UI will call the CreateCertificate method (passing arguments, etc) and the method may return something also.
UI将调用CreateCertificate方法(传递参数等),该方法也可能返回一些东西。
NOTE: If you want the class to act on the UI though then create a controller class (if you are doing MVC) or a presenter class (if you are doing MVVM, and don't want to put everything inside the ViewModel) and use the GiftCertificateService from that class.
注意:如果您希望该类在UI上操作,然后创建一个控制器类(如果您正在做MVC)或一个presenter类(如果您正在做MVVM,并且不想把所有东西都放到ViewModel中),并使用该类的gift证书。