【问题标题】:What is the best approach to make data access methods in NHibernate?在 NHibernate 中制作数据访问方法的最佳方法是什么?
【发布时间】:2010-11-20 11:56:19
【问题描述】:

例如,我有两个类:Foo 和 Bar。这些类映射到一些表。

目前,我对每个类都有静态方法:添加、更新、删除、获取。

E.g.: 

public class Foo
{
   private Guid _id;
   private string _someProperty;

   static Foo Get(Guid id);
   static void Add(Foo foo);
   static void Update(Foo foo);
   static void Delete(Foo foo);
}

所以,当我需要对我的对象做某事时,我会这样说:

Foo foo = Foo.Get(id);

Foo newfoo = new Foo();
Foo.Add(newfoo);

Foo.Update(newfoo);

Foo.Delete(newfoo);

这是一个好方法吗? 如果不是,我应该使用什么方法来访问数据?

谢谢

【问题讨论】:

  • 我同意@kitsune 关于使用存储库的观点。但是,如果您想要活动记录方法,您可以使用 Castle Active Record,并在后台使用 nhibernate 进行数据访问。我已经用过几次了,非常适合小型项目。

标签: c# nhibernate data-access-layer static-methods


【解决方案1】:

您所做的基本上是Active Record 模式的实现。许多人使用它,这是一种完全有效的方法。但是,如果您的应用程序非常复杂,或者如果您对关注点分离有一种迷恋,您可能会发现以下内容很有帮助:

我推荐 DDD (domain-driven design) 方法。 DDD 使用所谓的存储库模式。 DDD 将您的应用程序及其关注点分成不同的层,“模型/域”、“基础设施”和“服务”。

存储库是属于基础架构层内部的一种模式。像CustomerEmployer(或MonsterWeapon)这样的业务对象位于模型层内,代表您的“域”(您尝试建模)的核心,它们还负责业务逻辑.服务层可用于简化、编排跨多个模型的活动。

对于每个域模型(例如,您的类 Foo 和 Bar),您都有一个处理数据库访问的存储库。有了这个,你的数据库调用和模型就分开了。

public interface IFooRepository
{
     Foo Get(Guid guid);
}

public class FooRepository : IFooRepository
{
     public Foo Get(Guid guid)
     {
         //... DB voodoo magic happening
         return foo;
     }
}

如果您厌倦了一直为存储库编写锅炉代码,您也可以创建一个通用的 IRepository<T>

您还应该研究依赖注入/控制反转,因为这种方法非常适用。

这种方法的好处是,您可以轻松实现从 IFooRepository 派生的新类。这使您可以快速适应数据库基础架构中的更改。例如,您可以创建一个从 XML 文件读取数据的 FooRepository,或者使用 NHibernate 从 Postgres db 读取数据的一个。

您还可以阅读thisthisthis article 了解 DDD。

【讨论】:

  • 作为一个警告,ddd 一开始可能非常复杂,它的术语是“值对象”和“聚合根”等。不要绝望。
  • 当您尝试对关系建模时尤其如此。 (例如,一个Employee对象引用了一个Manager。如果你保存一个Employer会发生什么,你是否也必须保存它的Manager?谁负责保存它?)最后一段的第一篇文章,由吉米博加德,处理这个。
  • 感谢您的回答。我将尝试使用存储库模式来查看它是否适合我。你使用了 Active Record 模式吗?存储库模式是否让代码更干净?
【解决方案2】:

这始终取决于您编写的软件类型。

就我个人而言,我不喜欢实体本身是否进行任何数据访问。实体只负责管理其字段和属性,不应做更多。

在我正在开发的一个相当大的企业软件中,我们将所有 NH 访问权限放在一个单独的程序集中。 HQL 和其他特定的东西不属于业务逻辑。这也使得单元测试变得容易。有a similar architecture explained on CodeProject,值得一读。

我喜欢有一些允许插入、删除和更新任何实体的通用方法,因为使用 NH 非常简单,您不必一遍又一遍地编写相同的代码。例如:

void Store(object entity);
void Delete(object entity);
T Get<T>(object id);
IList<T> GetAll<T>();
void Lock(object entity);

特定接口中的其他特定方法,例如:

IList<Product> GetProductsWithAttribute(string attributeName, string attributeValue);

【讨论】:

    【解决方案3】:

    如果您正在编写大型应用程序,那么 Kitsune 所说的就是最好的方法。

    如果它是一小部分类,比如少于 5 个,并且永远不会成为大型企业应用程序,您可以查看此 NHibernate query helper (shameless plug) 或 Codesmith 生成其 NHibernate classes 的方式。

    通过第一个链接,您只需让您的对象保存数据,对业务规则执行任何验证:例如,使用名为 IsValidEmail() 的方法。然后,您使用查询管理器执行 Create、Read、Update、Delete 任务,例如:

    NHibernateManager<User> manager = new NHibernateManager<User>();
    User name = manager.ReadFirst();
    
    // All items filtered (using OR)
    IList<User> list = manager.OrList("@Name", "12345", "@Name", "54321");
    
    // Paged
    list = manager.Page(1,10);
    

    CodeSmith 模板比这更高级,但工作原理相似。它们向您展示 NHibernate 会话。

    您所做的 ActiveRecord 模式也非常好,只会被领域驱动的纯粹主义者鄙视。唯一的问题是诸如 User、Contact 等对象负责 NHibernate 查询和会话,但相反,该对象是自包含的。

    在 2 种(或 3 种,如果您包含存储库模式)中,您更愿意使用哪一种?最终哪一个最适合您的项目?

    【讨论】:

    • 嗯,您建议的 NHibernateManager 看起来与存储库模式非常相似。由于我有 20 多个实体,我想我会尝试使用存储库模式(我会用我的实体创建一些测试项目,看看它对我来说是否更好)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-02
    • 1970-01-01
    • 1970-01-01
    • 2010-09-05
    • 2020-04-10
    • 2011-11-22
    • 1970-01-01
    相关资源
    最近更新 更多