关于这个问题,即使有很多问答,我也没有找到这个问题的明确答案:
向实体类添加业务规则(即验证)的最佳设计实践是什么。
我只想在设置基础实体值之前检查一些验证:
public Property
{
get { return base.Property; }
set
{
// Do some validations or other business logic
base.Property = value;
}
}
当实体类中已存在所有属性时,在BLL中从头开始创建新类是没有意义的。另一方面,实体类需要使用业务逻辑规则进行扩展。
使用接口需要额外的工作,因为DAL(实体)的更改将反映在接口和BLL类中。
我不确定是否继承实体类并覆盖它的属性并添加额外的属性和方法是一个好主意。
示例伪代码对我更有帮助。
由于
答案 0 :(得分:4)
我想详细说明Stephen Cleary的回答。他使用部分类/方法来处理EF中的业务规则是正确的。但是,他没有详细说明在该部分类/方法中该做什么。我在我的博客上创建了一个URL缩短服务,以此作为示例。我的ShortURL
实体只有两列/属性。 Url
和ID
。
我想验证缩短的URL是否有效,然后才能通过EF将其实际存储到数据库中。所以我创建了一个类似的部分类和方法:
public partial class ShortURL
{
partial void OnUrlChanging(string url)
{
if (!Regex.IsMatch(url, @"(^((http|ftp|https):\/\/|www\.)[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?)"))
throw new Exception("Not a valid URL.");
}
}
这使EF停止更改属性,使其保持为NULL。但就是这样。它没有给我一个简单的方法来获取错误消息并将其显示给用户(我知道编辑:根据http://www.sellsbrothers.com/posts/Details/12700 IDataErrorInfo是获取的唯一方法在ASP.NET MVC中正确显示的错误消息)所以我跟着另一个我在网络的黑暗凹槽中找到的例子,我让我的部分类继承自IDataErrorInfo
。然后我实现了接口并包含一个私有字典对象来存储错误消息。
public partial class ShortURL : IDataErrorInfo
{
private Dictionary<string, string> errors = new Dictionary<string, string>();
partial void OnUrlChanging(string url)
{
if (!Regex.IsMatch(url, @"(^((http|ftp|https):\/\/|www\.)[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?)"))
errors.Add("Url", "Not a valid URL.");
}
public string Error
{
get { return string.Empty; } //I never use this so I just return empty.
}
public string this[string columnName]
{
get
{
if (errors.ContainsKey(columnName))
return errors[columnName];
return string.Empty; //Return empty if no error in dictionary.
}
}
}
现在,我有一个完整功能的方法来存储,检索和显示错误消息。现在回到我的控制器(在MVC中),我能够if (!ModelState.IsValid)
[HttpPost]
public ViewResult URLShortener(ShortURL shortURL)
{
if (!ModelState.IsValid)
return View();
shortURL.Url = shortURL.Url.ToLower().StartsWith("www.") ? "http://" + shortURL.Url : shortURL.Url;
shortURLRepository.AddShortURL(shortURL);
object model = "http://www.u413.com/" + ShortCodes.LongToShortCode(shortURL.UrlID);
//Not related to this answer but I had to cast my string as a generic object because the View() method has a (string, string) constructor that does something totally different. My view actually uses string as the model. I know I know, I could have just used ViewBag.
return View("ShowUrl", model);
}
你去吧。一个工作示例,不仅如何扩展EF的部分方法,还包括如何将验证传播回UI。如果有任何需要改进或者我有什么遗漏,请告诉我。
答案 1 :(得分:3)
查看您的EF设计器生成的代码。
每个属性Property
实际上都是这样实现的:
public global::System.String Property
{
get
{
return _Property;
}
set
{
OnPropertyChanging(value);
ReportPropertyChanging("Property");
_Property = StructuralObject.SetValidValue(value, false);
ReportPropertyChanged("Property");
OnPropertyChanged();
}
}
private global::System.String _Property;
partial void OnPropertyChanging(global::System.String value);
partial void OnPropertyChanged();
部分方法On-Property-Changing
是您可以执行单属性验证或业务逻辑的地方。
答案 2 :(得分:2)
Xaqron,我发现它使用Partial Classes的最好方法,例如,如果你的EF中有一个名为PropertyListing的类,你可以使用这样的部分类:
Partial Public Class PropertyListing
Inherits EntityObject
'Do something here
End Class
现在,您可以根据需要尽可能少地扩展课程,而不必大惊小怪。这个例子是在VB中,但是你得到了它的jist