C# 数据访问层到业务对象的最佳“模式”
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/644941/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Best "pattern" for Data Access Layer to Business Object
提问by Dave Baghdanov
I'm trying to figure out the cleanest way to do this.
我试图找出最干净的方法来做到这一点。
Currently I have a customer object:
目前我有一个客户对象:
public class Customer
{
public int Id {get;set;}
public string name {get;set;}
public List<Email> emailCollection {get;set}
public Customer(int id)
{
this.emailCollection = getEmails(id);
}
}
Then my Email object is also pretty basic.
然后我的 Email 对象也很基本。
public class Email
{
private int index;
public string emailAddress{get;set;}
public int emailType{get;set;}
public Email(...){...}
public static List<Email> getEmails(int id)
{
return DataAccessLayer.getCustomerEmailsByID(id);
}
}
The DataAccessLayer currently connects to the data base, and uses a SqlDataReader to iterate over the result set and creates new Email objects and adds them to a List which it returns when done.
DataAccessLayer 当前连接到数据库,并使用 SqlDataReader 迭代结果集并创建新的 Email 对象并将它们添加到完成后返回的 List 中。
So where and how can I improve upon this?
那么我可以在哪里以及如何改进呢?
Should I have my DataAccessLayer instead return a DataTable and leave it up to the Email object to parse and return a List back to the Customer?
我是否应该让我的 DataAccessLayer 返回一个 DataTable 并将其留给 Email 对象来解析并将列表返回给客户?
I guess "Factory" is probably the wrong word, but should I have another type of EmailFactory which takes a DataTable from the DataAccessLayer and returns a List to the Email object? I guess that kind of sounds redundant...
我猜“工厂”可能是错误的词,但我应该有另一种类型的 EmailFactory,它从 DataAccessLayer 获取一个 DataTable 并将一个 List 返回给 Email 对象?我想那种听起来多余...
Is this even proper practice to have my Email.getEmails(id) as a static method?
这甚至是将我的 Email.getEmails(id) 作为静态方法的正确做法吗?
I might just be throwing myself off by trying to find and apply the best "pattern" to what would normally be a simple task.
我可能只是试图找到最好的“模式”并将其应用到通常很简单的任务中,从而让自己失望。
Thanks.
谢谢。
Follow up
跟进
I created a working example where my Domain/Business object extracts a customer record by id from an existing database. The xml mapping files in nhibernate are really neat. After I followed a tutorial to setup the sessions and repository factories, pulling database records was pretty straight forward.
我创建了一个工作示例,其中我的域/业务对象通过 id 从现有数据库中提取客户记录。nhibernate 中的 xml 映射文件真的很整洁。在我按照教程设置会话和存储库工厂之后,提取数据库记录非常简单。
However, I've noticed a huge performance hit.
但是,我注意到了巨大的性能损失。
My original method consisted of a Stored Procedure on the DB, which was called by a DAL object, which parsed the result set into my domain/business object.
我的原始方法由一个 DB 上的存储过程组成,该过程由 DAL 对象调用,该对象将结果集解析为我的域/业务对象。
I clocked my original method at taking 30ms to grab a single customer record. I then clocked the nhibernate method at taking 3000ms to grab the same record.
我用原来的方法计时,需要 30 毫秒才能获取单个客户记录。然后我将 nhibernate 方法计时为 3000 毫秒以获取相同的记录。
Am I missing something? Or is there just a lot of overhead using this nhibernate route?
我错过了什么吗?或者使用这个 nhibernate 路由有很多开销吗?
Otherwise I like the cleanliness of the code:
否则我喜欢代码的整洁:
protected void Page_Load(object sender, EventArgs e)
{
ICustomerRepository repository = new CustomerRepository();
Customer customer = repository.GetById(id);
}
public class CustomerRepository : ICustomerRepository
{
public Customer GetById(string Id)
{
using (ISession session = NHibernateHelper.OpenSession())
{
Customer customer = session
.CreateCriteria(typeof(Customer))
.Add(Restrictions.Eq("ID", Id))
.UniqueResult<Customer>();
return customer;
}
}
}
The example I followedhad me create a helper class to help manage the Session, maybe that's why i'm getting this overhead?
我遵循的示例让我创建了一个帮助程序类来帮助管理会话,也许这就是我得到这个开销的原因?
public class NHibernateHelper
{
private static ISessionFactory _sessionFactory;
private static ISessionFactory SessionFactory
{
get
{
if (_sessionFactory == null)
{
Configuration cfg = new Configuration();
cfg.Configure();
cfg.AddAssembly(typeof(Customer).Assembly);
_sessionFactory = cfg.BuildSessionFactory();
}
return _sessionFactory;
}
}
public static ISession OpenSession()
{
return SessionFactory.OpenSession();
}
}
With the application i'm working on, speed is of the essence. And ultimately a lot of data will pass between the web-app and the database. If it takes an agent 1/3 of a second to pull up a customer record as opposed to 3 seconds, that would be a huge hit. But if i'm doing something weird and this is a one time initial setup cost, then it might be worth it if the performance was just as good as executing stored procedures on the DB.
对于我正在处理的应用程序,速度至关重要。最终,大量数据将在 Web 应用程序和数据库之间传递。如果代理需要 1/3 秒而不是 3 秒来提取客户记录,那将是一个巨大的打击。但是如果我正在做一些奇怪的事情并且这是一次性的初始设置成本,那么如果性能与在数据库上执行存储过程一样好,那么它可能是值得的。
Still open to suggestions!
仍然愿意接受建议!
Updated.
更新。
I'm scrapping my ORM/NHibernate route. I found the performance is just too slow to justify using it. Basic customer queries just take too long for our environment. 3 seconds compared to sub-second responses is too much.
我正在废弃我的 ORM/NHibernate 路线。我发现性能太慢而无法证明使用它是合理的。对于我们的环境来说,基本的客户查询花费的时间太长了。3 秒与亚秒级响应相比太多了。
If we wanted slow queries, we'd just keep our current implementation. The idea to rewrite it was to drastically increase times.
如果我们想要慢速查询,我们只需要保留我们当前的实现。重写它的想法是大大增加时间。
However, after having played with NHibernate this past week, it is a great tool! It just doesn't quite fit my needs for this project.
然而,在上周玩过 NHibernate 之后,它是一个很棒的工具!它只是不太适合我对这个项目的需求。
采纳答案by James Orr
If the configuration you've got works now, why mess with it? It doesn't sound like you're identifying any particular needs or issues with the code as it is.
如果您的配置现在有效,为什么还要搞砸呢?听起来您并没有确定代码的任何特定需求或问题。
I'm sure a bunch of OO types could huddle around and suggest various refactorings here so that the correct responsibilities and roles are being respected, and somebody might even try to shoehorn in a design pattern or two. But the code you have now is simple and sounds like it doesn't have any issues - i'd say leave it.
我敢肯定,一堆 OO 类型可能会挤在一起,并在这里提出各种重构建议,以便尊重正确的职责和角色,有人甚至可能会尝试硬塞进一两个设计模式。但是您现在拥有的代码很简单,听起来没有任何问题 - 我会说离开它。
回答by George Mauer
I've implemented a DAL layer by basically doing what NHibernate does but manually. What NHibernate does is create a Proxy class that inherits from your Domain object (which should have all its fields marked as virtual). All data access code goes into property overrides, its pretty elegant actually.
我已经实现了一个 DAL 层,基本上是通过手动完成 NHibernate 所做的。NHibernate 所做的是创建一个从您的域对象(应该将其所有字段标记为虚拟)继承的代理类。所有数据访问代码都进入属性覆盖,实际上它非常优雅。
I simplified this somewhat by having my Repositories fill out the simple properties themselves and only using a proxy for Lazy loading. What I ended up is a set of classes like this:
我通过让我的存储库自己填写简单的属性并仅使用代理进行延迟加载来稍微简化了这一点。我最终得到的是一组这样的类:
public class Product {
public int Id {get; set;}
public int CustomerId { get; set;}
public virtual Customer Customer { get; set;}
}
public class ProductLazyLoadProxy {
ICustomerRepository _customerRepository;
public ProductLazyLoadProxy(ICustomerRepository customerRepository) {
_customerRepository = customerRepository;
}
public override Customer {
get {
if(base.Customer == null)
Customer = _customerRepository.Get(CustomerId);
return base.Customer
}
set { base.Customer = value; }
}
}
public class ProductRepository : IProductRepository {
public Product Get(int id) {
var dr = GetDataReaderForId(id);
return new ProductLazyLoadProxy() {
Id = Convert.ToInt(dr["id"]),
CustomerId = Convert.ToInt(dr["customer_id"]),
}
}
}
But after writing about 20 of these I just gave up and learned NHibernate, with Linq2NHibernate for querying and FluentNHibernate for configuration nowadays the roadblocks are lower than ever.
但是在写了大约 20 个之后,我放弃了并学习了 NHibernate,使用 Linq2NHibernate 进行查询,使用 FluentNHibernate 进行配置,现在障碍比以往任何时候都低。
回答by Chris S
This may be too radical for you and doesn't really solve the question, but how about completely scrapping your data layer and opting for an ORM? You will save a lot of code redundancy that spending a week or so on a DAL will bring.
这对您来说可能过于激进,并不能真正解决问题,但是完全取消数据层并选择 ORM 怎么样?您将节省在 DAL 上花费一周左右会带来的大量代码冗余。
That aside, the pattern you're using resembles a repository pattern, sort of. I'd say your options are
除此之外,您使用的模式类似于存储库模式。我会说你的选择是
- A service object in your Email class - say EmailService - instantiated in the constructor or a property. Accessed via an instance such as email.Service.GetById(id)
- A static method on Email, like Email.GetById(id) which is a similar approach
- A completely separate static class that is basically a fa?ade class, EmailManager for example, with static methods like EmailManager.GetById(int)
- The ActiveRecord pattern where you are dealing with an instance, like email.Save() and email.GetById()
- 您的 Email 类中的服务对象 - 例如 EmailService - 在构造函数或属性中实例化。通过 email.Service.GetById(id) 等实例访问
- 电子邮件上的静态方法,例如 Email.GetById(id),这是一种类似的方法
- 一个完全独立的静态类,基本上是一个外观类,例如 EmailManager,具有像 EmailManager.GetById(int) 这样的静态方法
- 您正在处理实例的 ActiveRecord 模式,例如 email.Save() 和 email.GetById()
回答by David Walschots
Most likely your application has its domain logic setup in transaction scripts. For .NET implementations that use transaction script Martin Fowler recommends the usage of the table data gatewaypattern. .NET provides good support for this pattern because the table data gateway pattern is great with record set, which Microsoft implements with its DataSet-type classes.
很可能您的应用程序在事务脚本中设置了域逻辑。对于使用事务脚本的 .NET 实现,Martin Fowler 建议使用表数据网关模式。.NET 为这种模式提供了很好的支持,因为表数据网关模式非常适合记录集,Microsoft 使用其 DataSet 类型的类实现了记录集。
Various tools within the Visual Studio environment should increase your productivity. The fact that DataSets can easily be databound to various controls (like the DataGridView) makes it a good choice for data-driven applications.
Visual Studio 环境中的各种工具应该可以提高您的工作效率。DataSet 可以轻松地绑定到各种控件(如 DataGridView),这一事实使其成为数据驱动应用程序的不错选择。
If your business logic is more complex than a few validations a domain modelbecomes a good option. Do note that a domain model comes with a whole different set of data access requirements!
如果您的业务逻辑比一些验证更复杂,那么域模型将成为一个不错的选择。请注意,域模型带有一组完全不同的数据访问要求!