【问题标题】:Create Custom Criterion in NHibernate?在 NHibernate 中创建自定义标准?
【发布时间】:2012-06-22 20:50:57
【问题描述】:

在谈到 NHibernate 时,我仍然是一个 n00b。假设我有以下内容:

var myCriteria = this.Session.CreateCriteria(typeof(SomeModel))
                         .Add(Restrictions.Eq("SomeProperty", someValue);

然后,假设我想以可重用的方式添加条件。意思是,我想制定一个自定义标准。我在网上看到的关于这方面的信息非常非常少。具体来说,我想转以下:

var myCriteria = this.Session.CreateCriteria(typeof(SomeModel))
                .Add(Restrictions.Eq("SomeProperty", someValue)
                .CreateAlias("SomeClass", "alias", JoinType.LeftOuterJoin)
                .Add(Restrictions.Eq("alias.SomeOtherProperty", someOtherValue));

如下:

var myCriteria = this.Session.CreateCriteria(typeof(SomeModel))
                             .Add(Restrictions.Eq("SomeProperty", someValue)
                             .Add(this.GetAliasCriterion());

从而提取

      .CreateAlias("SomeClass", "alias", JoinType.LeftOuterJoin)
             .Add(Restrictions.Eq("alias.SomeOtherProperty", someOtherValue)); 

进入一个方法。

这可能吗?这是如何工作的?

【问题讨论】:

  • 你为什么不尝试使用 DetachedCriteria

标签: .net nhibernate nhibernate-criteria


【解决方案1】:

就个人而言,我更喜欢使用 Linq to NHibernate 而不是标准。它已经包含在最新版本的 NHibernate 中,只需将“using NHibernate.Linq”添加到您的 cs 文件中,因为所有 L2H 方法都是扩展方法。

如果我想让一个谓词/标准可在 L2H 中重复使用,它看起来像这样:

public partial class Person 
{
    //yes, this is kind of ugly, but if I have a complicated predicate that 
    //I want to reuse, I'll make a static method on the entity itself.
    public static Expression<Func<Person, bool>> HasPrimaryRole(string roleCode)
    {
        return p => p.Roles.Any(r => r.RoleCode == roleCode && r.IsPrimary);
    }
}

用法如下:

var session = GetSession();
var midwestSalesManagers = session.Query<Person>()
    .Where(p => p.Region == "Midwest").Where(Person.HasPrimaryRole("RSM"));

或者你也可以这样做:

var midwestSalesManagers = session.Query<Person>()
    .Where(Expression.And(p => p.Region == "Midwest", Person.HasPrimaryRole("RSM")));

我还没有完全测试所有这些,但我希望你明白我的意思。我认为它的可读性很好,并且避免使用魔术字符串,所以它对重构很友好。

【讨论】:

  • 天啊,那个语法好多了。让我们看看我能否让整个 20 人的团队扭转方向并重写他们的整个数据访问层……是的,这可能不会发生。太糟糕了,这是我第一次使用 NHibernate,而我在这个项目上投入了几个月的时间:/谁知道呢,也许他们不会介意我这样写新东西?
【解决方案2】:

这是我经常使用的模式:

假设我有一个过滤器,它在标准上添加特定的Restrictions。 (您甚至可以将其设为扩展类)

public class DeletedFlagFilter{

  public DetachedCriteria AddFilter(DetachedCriteria criteria)
  {
        criteria.AddRestrictions("Deleted", true);
        return criteria;
  }
}

上述类的调用者说(FindDeletedUserClass)然后将使用上面的帮助类添加所有必要的限制来定义删除的用户,如下所示:

   public class FindDeletedUserClass{

      public DetachedCriteria BuildCriteria(){

             var deletedUserCriteria = DetachedCriteria.For<User>();          

             var helper = new DeletedFlagFilter();

             helper.AddFilter(deletedUserCriteria);

             return deletedUserCriteria;

      }
 }

实际访问 NHibernate Session 的分离服务层然后可以将 DetachedCriteria 转换为连接到会话的标准并执行相同的操作。

  var myDetachedCriteria = DetachedCriteria.For<SomeModel>();

  var sessionCriteria = myDetachedCriteria.GetExecutableCriteria(Session);

使用上面的模式,您可以将 Deleted 功能封装在 DeletedFlagFilter 类中。将来,如果 Deleted 的定义发生更改,则唯一的更改将发生在 DeletedFlagFilter 类上

编辑:有很好的教程,你可以阅读here

【讨论】:

  • 谢谢。我会检查那个链接。我明白了,这似乎是一种可能性。我支持你,如果这正是我需要的,我会接受这个答案。无论哪种方式,仍然是一个很好的建议。
【解决方案3】:

您可以使用扩展方法来做到这一点。不过我会小心,通常您会希望查看查询正在执行的所有别名(连接)。

public static class CriteriaExtensions
{
    public static ICriteria AddSomeClassAliasRestriction(this ICriteria c, object value)
    {
        return c.CreateAlias("SomeClass", "alias", JoinType.LeftOuterJoin)
            .Add(Restrictions.Eq("alias.SomeOtherProperty", value));
    }
}

并像...一样使用它

var myCriteria = this.Session.CreateCriteria(typeof(SomeModel))
.Add(Restrictions.Eq("SomeProperty", someValue)
.AddSomeClassAliasRestriction(someOtherValue);

【讨论】:

  • 这对于某些场景来说是一个很好的建议,但不是我的。所以我会对此表示赞同并记住它以备将来使用。但这不是我想用于多个 DAO 类的东西。
  • 嗯,好的,你能更新一下你的问题吗?目前尚不清楚您要问什么。
  • 我要说的是,当它不会在一个类之外使用时制作一个扩展方法有点矫枉过正。但它会起作用,因此赞成。
  • 哦,这很容易转移到常规方法。
猜你喜欢
  • 1970-01-01
  • 2010-09-18
  • 1970-01-01
  • 2011-06-15
  • 1970-01-01
  • 2017-08-20
  • 1970-01-01
  • 1970-01-01
  • 2014-09-14
相关资源
最近更新 更多