NHibernate - Ограничения LINQ - PullRequest
       13

NHibernate - Ограничения LINQ

2 голосов
/ 13 октября 2010

Я использую Nhibernate вместе с LINQ, и у меня есть несколько проблем. Скажем, у меня есть следующие объекты:

public class User
{
    public virtual int UserID { get; set; }
    public virtual bool IsActive { get; set; }
    public virtual bool SomeField { get { return 0; } }
    public virtual DateTime DateRegistered { get; set; }
    public virtual IList<Membership> Membership { get; set; }
    public virtual Membership ValidMembership { get { return Membership.FirstOrDefault(m => m.IsValid); } }
}

public class User2
{
    public virtual int UserID { get; set; }
    public virtual int MembershipID { get; set; }
}

public class Membership
{
    public virtual int MembershipID { get; set; }
    public virtual bool IsValid { get; set; }
}

Теперь, если я выполню следующий запрос:

var users = service.Linq<User>()
    .Where(u => u.IsActive) // This would work
    .Where(u => u.SomeField > 0) // This would fail (i know i can map these using formulas but this is here to illustrate)
    .Where(u => u.Membership.Any(m => m.IsValid)) // This would work
    .Where(u => u.ValidMembership != null) // This would fail
    .Where(u => u.DateRegistered > DateTime.UtcNow.AddDays(-1)) // This would work
    .Where(u => u.DateRegistered.AddDays(1) > DateTime.UtcNow) // This would fail
    .Select(u => new User2 { UserID = u.UserID }) // This would work
    .Select(u => u.UserID) // This would work
    .Select(u => new { UserID = u.UserID }) // This would fail
    .Select(u => new User2 { UserID = u.UserID, MembershipID = u.Membership.Any(m => m.IsValid) ? u.Membership.Any(m => m.IsValid).First().MembershipID : 0 }); // This would fail

Я добавил комментарий рядом с каждым, чтобы указать, сработают они или нет. Это те сценарии, о которых я могу подумать в данный момент. Мне удалось преодолеть эти проблемы, преобразовав данные в список, прежде чем он сделает что-то слишком причудливое. Это, очевидно, влияет на производительность. Мне было интересно, будут ли их поддерживать будущие версии поставщика LINQ для NHibernate? Также кто-нибудь знает, как структура сущностей будет обрабатывать эти сценарии. Я полагаю, что структура сущностей будет улучшением, но я не хочу прыгать с корабля, если существуют такие же проблемы.

ценим ваши отзывы. Спасибо

Ответы [ 4 ]

3 голосов
/ 13 октября 2010

NHibernate 3 поддерживает больше конструкций, чем используемый вами поставщик contrib (только что вышла Beta1, окончательная версия ожидается до конца года)

Однако, как отмечали другие, некоторые конструкции сложны(или невозможно) анализировать, в то время как другие требуют очень специфического кода для перевода деревьев выражений в SQL.

К счастью, новый поставщик также расширяем, что означает, что вы можете добавить свою собственную логику БД для собственных методовили которые не поддерживаются "из коробки".

1 голос
/ 14 октября 2010

Это дополнение к ответу Диего Миджельшона

  • Расчетные свойства никогда не могут быть проанализированы поставщиком Linq из коробки, поскольку тела методов не могут быть преобразованы в дерево выражений.
  • Некоторые или, может быть, даже все не реализованные проблемы реализованы в текущем поставщике Linq.

    Где (u => u.SomeField> 0) // Вычисляемое свойство SomeField

    Где (u => u.ValidMembership! = Null) // Вычисляемое свойство ValidMembership

    Где (u => u.DateRegistered.AddDays (1)> DateTime.UtcNow) // Метод DateTime.AddDays не реализован для этой стороны оператора сравнения дат, превышающего>

    Выберите (u => new {UserID = u.UserID}) // Создание анонимных объектов не реализовано

    Выберите (u => новый User2 {UserID = u.UserID, MembershipID = u.Membership.Any (m => m.IsValid)? U.Membership.Any (m => m.IsValid) .First () .MembershipID: 0}); // Тернарный оператор не реализован

1 голос
/ 13 октября 2010

Этот код даже не должен компилироваться. User.SomeField - логическое свойство, но вы пытаетесь вернуть 0 из геттера? SomeField и ValidMemberships не должны быть даже виртуальными, потому что они являются полем, которое даже не будет управляться NHibernate.

0 голосов
/ 13 октября 2010

Entity Framework потерпит неудачу в тех же случаях, что и NHibernate (по крайней мере, для ваших примеров). Помните, Linq использует отложенную загрузку для операций Where () - и все в Linq2SQL (включая Entity Framework) и Linq2NHibernate необходимо преобразовать в SQL при отложенной загрузке. Вызовы методов не могут быть преобразованы в SQL - нет представления метода в SQL - и поэтому он потерпит неудачу.

Когда вы используете ToList () - вы заставляете предыдущие операторы Linq вычислять (до вызова базы данных), а затем работаете вперед, вы работаете с представлением в памяти, позволяющим вам использовать полные деревья выражений Linq2Object (которые иметь возможность модных вызовов методов и т. д.)

Что касается ваших проекций - я бы не стал использовать Linq2NHibernate для них - вместо этого используйте проекции, встроенные в «стандартный» NHibernate.

...