Создать пользовательский критерий в 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
учебный класс
Изменить: есть хороший учебник, который вы можете прочитать здесь