【发布时间】:2011-09-02 13:52:54
【问题描述】:
我创建了一个 POCO 模型类和一个处理持久性的存储库类。由于 POCO 无法访问存储库,因此存储库中有很多业务逻辑任务似乎不正确。根据我的阅读,我似乎需要一个位于 UI 消费者和存储库层之间的服务层。我不确定它应该如何工作......
除了服务层,是不是应该还有一个单独的业务逻辑层,还是说服务层的作用?
每个存储库应该有一个服务吗?
服务层是 UI 可以实例化模型对象的唯一方式,还是存储库向服务提供新模型实例?
我是否将我的参数、模型和其他验证放在服务层中以执行检查以确保输入有效以及更新前数据库中是否存在要更新的项目?
模型、存储库和 UI 是否都可以调用服务层,还是只是供 UI 使用?
服务层应该都是静态方法吗?
从 UI 调用服务层的典型方法是什么?
模型与服务层应该进行哪些验证?
这是我现有图层的一些示例代码:
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;
}
}
更新: 我目前正在使用 Web 表单和经典的 ADO.NET。我希望最终转向 MVC 和 EF4。
更新:非常感谢@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
}
}
问题
我是否向服务中添加了与我的模型(数量、代码等)相同(可能更多)的属性,还是只提供接受 GiftCertificate 对象和直接参数的方法?
我是在调用 Service 构造函数时创建 GiftCertificate 实体的默认实例,还是只根据需要创建新实例(例如 - 对于需要调用实体中的验证方法的服务中的验证方法?另外,关于创建默认存储库实例的同样问题...?
我知道我通过服务公开了 repo 的功能,我是否也公开了实体的方法(例如 - IsValidCode 等)?
UI 可以直接创建一个新的 GiftCertificate 对象而无需通过服务(例如 - 从实体调用参数验证方法)。如果没有,如何执行?
在 UI 层,当我想创建新的礼券时,我是直接从 UI 层调用模型/服务验证(如 IsValidExpirationDate 等)还是先水合对象,然后通过是否要对其进行验证,然后将某种验证摘要返回给 UI?
另外,如果我想从 UI 层进行兑换,我是否首先从 UI 调用模型/服务验证方法以提供用户反馈,然后调用将在内部再次运行相同检查的 Redeem 方法?
从 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);
从 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...
在创建 GC 的方式以及如何在实体/服务之间分离验证方面感觉有些不对劲。用户/消费者不必关心什么验证在什么地方......建议?
【问题讨论】:
标签: c# asp.net domain-driven-design repository repository-pattern