Создать пользовательский критерий в NHibernate?

Я все еще немного n00b, когда дело доходит до NHibernate. Допустим, у меня есть следующее:

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)); 

в метод.

Это возможно? Как это работает?

3 ответа

Решение

Лично я предпочитаю использовать Linq для 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")));

Я не полностью проверил все это, но я надеюсь, что вы поняли мой дрейф. Я думаю, что он довольно читабелен и позволяет избежать использования магических строк, поэтому он удобен для рефакторинга.

Вы можете сделать это с помощью метода расширения. Хотя я был бы осторожен, обычно вы хотите видеть все псевдонимы (объединения), которые выполняет запрос.

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);

Это шаблон, который я обычно использую:

Скажи, что у меня есть фильтр, который добавляет конкретные Restrictions по критериям. (Вы могли бы даже сделать это классом Extension)

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, может затем преобразовать DetachedCriteria в критерии, связанные с сеансом, и выполнить то же самое.

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

  var sessionCriteria = myDetachedCriteria.GetExecutableCriteria(Session);

Используя шаблон выше, вы бы инкапсулировали функциональность Deleted в DeletedFlagFilter учебный класс. В будущем, если определение " Удаленные изменения" произойдет, единственное изменение будет DeletedFlagFilter учебный класс

Изменить: есть хороший учебник, который вы можете прочитать здесь

Другие вопросы по тегам