1

У меня возникают проблемы с повторным использованием ProjectionLists в NHibernate QueryOvers. Я не могу понять, как повторно использовать вещи для разных корневых объектов.QueryOver ProjectionList с разными типами корневых сущностей

модель объекта грубо представлена ​​в виде:

завтрак один ко многим кондитерских изделий многих нулевой или-один Кофе

Две отдельные запросы примерно:

session.QueryOver<Breakfast>() 
    .Where(b => b.Id == searchId) 
    .Inner.JoinQueryOver(b => b.Pastries,() => pastry) 
    .Left.JoinAlias(p => p.Coffee,() => coffee) 
    .Select(projections) 
    .TransformUsing(Transformers.AliasToBean<TargetDto>()) 
    .List<TargetDto>(); 

session.QueryOver<Coffee>() 
    .Where(c => c.Id == searchId) 
    .Inner.JoinQueryOver(c => c.Pastries,() => pastry) 
    .Select(projections) 
    .TransformUsing(Transformers.AliasToBean<TargetDto>()) 
    .List<TargetDto>(); 

Общие проекции, которые я пытаюсь использовать, выглядят так:

var projections = Projections.ProjectionList() 
    .Add(Projections.Property(() => pastry.Name,() => target.PastryName)) 
    .Add(Projections.Property(() => coffee.Name,() => target.CoffeeName)); 

Эти проекции, используя псевдонимы, отлично работают для первого запроса (корень: завтрак), потому что они не пытаются удалить свойства, которые находятся на этом корневом объекте. Во втором запросе (root: Coffee) он взрывается, говоря, что он не может найти «coffee.Name» на Coffee, потому что ему не нравится псевдоним. Синтаксис QueryOver (() => coffee) не помогает, потому что он фактически не регистрирует «кофе» как псевдоним, он просто использует его для вывода типа. О, черт возьми, это была проблема. Существует глупая инфраструктура приложений, которая разбивает синтаксис псевдонима, чтобы на самом деле не использовать псевдоним под ним.

Второй запрос хочет проекции выглядеть следующим образом:

var projections = Projections.ProjectionList() 
    .Add(Projections.Property(() => pastry.Name,() => target.PastryName)) 
    .Add(Projections.Property<Coffee>(c => c.Name,() => target.CoffeeName)); 

Однако теперь это несовместимо с первым запросом.

Есть ли способ сделать это, поэтому я могу проецировать свойства, не зная, что такое тип сущности-корня?

ответ

1

Я думаю, что все, что вам нужно сделать, это назначить coffee псевдоним в session.QueryOver<Coffee> вызова:

Coffee coffee = null; 

session.QueryOver<Coffee>(() => coffee) 
    /* etc */ 

Ниже может быть совершенно не связаны с тем, что вы делаете, но я решил включить его в Если кто-то еще пишет код, который передает псевдонимы QueryOver.


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

NHibernate принимает выражение () => coffee и захватывает имя псевдонима, который вы используете из выражения (в данном случае, "coffee"), а затем использует его в сгенерированном SQL в качестве псевдонима. Это означает, что в зависимости от того, как структурирован ваш код, общие прогнозы, подобные этому, могут сломаться, если имена псевдонимов меняются.

Например, говорят, что вы имели следующий метод, возвращающий некоторые общие проекции:

public ProjectionList GetSharedProjections() 
{ 
    Coffee coffee = null; 
    TargetDTO target; 

    var projections = Projections.ProjectionList() 
     .Add(Projections.Property(() => coffee.CoffeeName) 
      .WithAlias(() => target.CoffeeName)); 

    return projections; 
} 

Тогда вы имели некоторый код, который вызывает ваш вспомогательный метод:

session.QueryOver<Coffee>(() => coffee) 
    .Select(GetSharedProjections()); 

Все будет работать, как fine-- если ваши псевдонимы совпадают. Второй кто-либо меняет любой из псевдонимов, но запрос не удастся.

Вы можете попытаться передать в качестве псевдонима к способу, как это:

public ProjectionList GetSharedProjections(Coffee coffeeAlias) 
{ 
    /* Same as above except with "coffeeAlias" 
} 

А затем передать в ваш псевдоним:

session.QueryOver<Coffee>(() => coffee) 
    .Select(GetSharedProjections(coffee)); 

Но это не будет работать. Помните, что NHibernate захватывает имя псевдонима и использует его непосредственно в сгенерированном SQL. Вышеприведенный код попытается использовать как "coffee", так и "coffeeAlias" в сгенерированном SQL и сработает.

Один из способов правильно сделать это (не надеясь, что никто не изменит псевдонимы) - это передать выражения и использовать их для восстановления имен свойств с правильными псевдонимами.

Вы бы создать вспомогательный метод, который строит доступ к свойству с помощью псевдонима и свойства:

public static PropertyProjection BuildProjection<T>(
    Expression<Func<object>> aliasExpression, 
    Expression<Func<T, object>> propertyExpression) 
{ 
    string alias = ExpressionProcessor.FindMemberExpression(aliasExpression.Body); 
    string property = ExpressionProcessor.FindMemberExpression(propertyExpression.Body); 

    return Projections.Property(string.Format("{0}.{1}", alias, property)); 
} 

Затем, вы можете изменить метод GetSharedProjections взять псевдоним в виде выражения:

public ProjectionList GetSharedProjection(Expression<Func<Coffee>> coffeeAlias) 
{ 
    TargetDTO target = null; 

    var projections = Projections.ProjectionList() 
     .Add(BuildProjection<Coffee>(coffeeAlias, c => c.CoffeeName)) 
      .WithAlias(() => target.CoffeeName); 
} 

Теперь вызова метода будет выглядеть следующим образом:

session.QueryOver<Coffee>(() => coffee) 
    .Select(GetSharedProjections(() => coffee)); 

Когда кто-то изменяет ваше имя псевдонима, вы закрыты. Вы также можете безопасно использовать этот метод среди многих запросов, не беспокоясь о том, что на самом деле является именем переменной псевдонимов.

Отказ от ответственности: Ниже ссылка на мой личный блог

Вы можете найти более подробную информацию о построении QueryOver запросов так here.

+0

Это было именно то решение! Я пробовал это раньше, но я только что нашел, что у моего приложения есть глупая настраиваемая инфраструктура, связывающая вызовы NHibernate, которые нарушили псевдоним версии QueryOver (() => blah). Я знаю проблемы с псевдонимами, было интересно вникать в реализации NHibernate. Я уже использовал выражение как обходное решение. В других новостях: woah. Ваш блог был единственной причиной, по которой мне удалось ** вообще ** получить что-то, работающее с QueryOver, и теперь вы здесь отвечаете на мои вопросы. БЛАГОДАРЯ! :-) –

Смежные вопросы