Принудительное использование Linq для nHibernate с Oracle как Linq для коллекций при сравнении столбцов, содержащих null

Предположим, у меня есть класс Man, определенный в nHibernate

public class Man
{
   public string Name {get;set;}
   public string WifeName{get;set;}
   public string OldestChildName {get;set;}
}

с некоторыми экземплярами:

Name   |WifeName   |OldestChildeName
-------+-----------+-----------------
Mike   |Penny      |Jenny
Bill   |           |Julia       
Tom    |Patricia   |Patricia
Peter  |           |
Bart   |Mellany    |

Чтобы выбрать всех людей, у которых имя старшего ребенка совпадает с именем их жены

var names = 
  from m in men
  where m.WifeName == m.OldestChildName
  select m.Name

Для Linq для коллекций возвращается Том и Питер. Но Linq to nHibernate to Oracle переводит это как:

SELECT 
    m.name
FROM
    men m
WHERE 
    m.WifeName = m.OldestChildName;

который возвращает только Том: при сравнении SQL с нулевым значением оценивается значение null, а значение null оценивается как ложное.


Я бы хотел, чтобы сгенерировали:

SELECT 
    m.name
FROM
    men m
WHERE 
    m.WifeName = m.OldestChildName
OR  (
        m.WifeName IS NULL
    AND m.OldestChildName IS NULL
    );

поэтому в linq мне нужно ввести:

var names = 
  from m in men
  where m.WifeName == m.OldestChildName
    || (m.WifeName == null && m.OldestChildName == null)
  select m.Name

Есть ли простой способ сообщить nHibernate о переводе сравнения равенства между двумя столбцами, допускающими значение NULL, в сравнение sql и проверку NULL?

Другими словами, есть ли способ использовать один и тот же запрос linq и получить одинаковые результаты независимо от того, используется ли он для коллекций или баз данных?

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


person realbart    schedule 24.11.2016    source источник
comment
Ваше представление о правильности неверно. В SQL нулевое значение не равно другому нулю. Одна недостающая часть информации не может считаться равной какой-то другой недостающей информации.   -  person Panagiotis Kanavos    schedule 24.11.2016
comment
Вы правы, я изменил название. В SQL значение null интерпретируется как неизвестное, и оно также неизвестно, если unknown равно unknown. В C # null интерпретируется как не имеющее значения. Отсутствие ценности равняется отсутствию ценности. Я понимаю обе точки зрения. В моей повседневной работе большинство реальных проблем соответствуют интерпретации C #. Итак, я ищу способ заставить мои запросы вести себя таким образом.   -  person realbart    schedule 24.11.2016
comment
Это было бы очень плохой идеей. Запросы просто так не работают. Вы сами запутаетесь и запутаете разработчиков кода. В худшем случае, как показывает ответ, вы получите чрезвычайно медленный код, не зная, почему   -  person Panagiotis Kanavos    schedule 24.11.2016
comment
@PanagiotisKanavos Помимо плохой идеи, каково решение проблемы? почему sql-запрос вызывает проблемы со стабильностью? Мне любопытны твои идеи в этом отношении.   -  person go..    schedule 24.11.2016
comment
Запрос не вызывает проблем со стабильностью. Проблема в производительности. Чтобы выполнить сравнение, сервер должен вычислить результаты для всех строк, а затем сравнить их. Без функций сервер может использовать индексированные значения для поиска и загрузки только соответствующих страниц данных. Вы можете легко увидеть разницу, проверив план выполнения для обоих запросов.   -  person Panagiotis Kanavos    schedule 24.11.2016
comment
linq! = sql. Поэтому, если я хочу предсказать результат men.Where (m.WifeName == m.FirstChildName), я действительно не хочу знать природу мужчин. Прямо сейчас я вижу много AsEnumarable и ToList в нашей базе кода только потому, что свойства sql проникают в linq.   -  person realbart    schedule 24.11.2016
comment
Мне было интересно, если фильтр (ayende.com/blog/3993/nhibernate-filters ) может это сделать?   -  person David Osborne    schedule 25.11.2016


Ответы (1)


Нужный вам sql-запрос.

select * from Stack
where COALESCE (wifeName,'')=COALESCE (OldestChildeName,'')

Выход. введите здесь описание изображения

Для этого вам нужно использовать Nhibernate queryover.

var left = Projections.SqlFunction("COALESCE",
NHibernateUtil.String,
Projections.Property<Stack>(pc => pc.OldestChildeName),
Projections.Constant(""));


var right = Projections.SqlFunction("COALESCE",
NHibernateUtil.String,
Projections.Property<Stack>(pc => pc.WifeName),
Projections.Constant("") );

var restriction = Restrictions.EqProperty(left, right);

var dd = contex.Session<Stack>().QueryOver<Stack>().Where(restriction).List();

Выход.

введите здесь описание изображения

введите здесь описание изображения

предлагаю заблокировать

person go..    schedule 24.11.2016
comment
Это заставит сервер базы данных сканировать всю таблицу. Применение функций к столбцам не позволяет серверу использовать индексы - person Panagiotis Kanavos; 24.11.2016
comment
У вас есть предложение получше? - person go..; 24.11.2016
comment
Просто используйте нулевую проверку. В этом нет ничего плохого. Проблема состоит в том, чтобы навязать семантику одного языка другому. - person Panagiotis Kanavos; 24.11.2016