Nhibernate - запрос отношения один-ко-многим с Linq - PullRequest
0 голосов
/ 04 января 2011

Я бы хотел запросить отношение «один ко многим» для объекта. Чтобы объяснить мою проблему дальше, представьте, что мое приложение имеет следующие объекты:

public class User {
    public virtual int UserID { get; set; }

    public virtual Membership CurrentMembership {
        get { return Membership.Single(m => m.IsValid); }
    }

    public virtual IList<Membership> Membership { get; private set; }

    public User() {
        Membership = new List<Membership>();
    }
}

public class Membership {
    public virtual int MembershipID { get; set; }
    public virtual User User { get; set; }
    public virtual DateTime StartDate { get; set; }
    public virtual DateTime? EndDate { get; set; }
    public virtual int DaysLeft { get; set; }
    public virtual bool IsValid { get; set; }

    public Membership() {
    }
}

Со следующим отображением Fluent (отображение не имеет значения, я привел это здесь только для справки):

public class UserMap : ClassMap<User> {
    public UserMap() {
        Table("Users");
        Id(x => x.UserID);
        HasMany(x => x.Membership)
            .KeyColumn("UserID")
            .Inverse()
            .Cascade.All();
    }
}

public class MembershipMap : ClassMap<Membership> {
    public MembershipMap() {
        Table("Membership");
        Id(x => x.MembershipID);
        References(x => x.User);
        Map(x => x.StartDate);
        Map(x => x.DaysLeft)
            .Formula("CASE WHEN EndDate IS NOT NULL AND dbo.DayDiff(GETUTCDATE(), EndDate) > 0 THEN dbo.DayDiff(GETUTCDATE(), EndDate) ELSE 0 END");
            // DayDiff is a udf which gets the number of days between two dates
        Map(x => x.IsValid)
            .Formula("CASE WHEN dbo.GetValidMembershipID(UserID) = MembershipID THEN 1 ELSE 0 END");
            // GetValidMembershipID is a udf which works out the valid membership id for this user
    }
}

Как видите, пользователь может иметь много членов. CurrentMembership (свойство против пользователя) возвращает членство против пользователя, где свойство IsValid имеет значение true (это будет справедливо только для одного членства против пользователя).

Теперь я хотел бы иметь возможность получить доступ ко всем пользователям, у которых на данный момент осталось менее 20 дней.

Моей первой попыткой было сказать:

session.Linq<User>().Where(u => u.CurrentMembership.DaysLeft < 20).ToList();

Но это выбросило ошибку:

"не удалось разрешить свойство: CurrentMembership of: User"

Это было отчасти ожидаемо, поскольку я не использовал сопоставление формул для этого свойства (как я использовал для свойств DaysLeft и IsValid в отношении членства). Я не вижу, как можно использовать сопоставление формул, кроме как для отображения строк, целых и bools. Затем я попытался сказать:

session.Linq<User>().Where(u => u.Membership.Single(m => m.IsValid).DaysLeft < 20).ToList();

Но это выкинуло ошибку:

"Ссылка на объект не установлена ​​для экземпляра объекта."

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

Буду признателен за помощь. Спасибо

1 Ответ

0 голосов
/ 05 января 2011

Вы используете старый поставщик LINQ в NHibernateContrib для NHibernate 2.1.Этот провайдер больше не поддерживается и не предпринимает активных действий.

Встроенный в синтаксис NHibernate 3.0 провайдер LINQ имеет значение session.Query<TEntity>() вместо session.Linq<TEntity>().

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

Я настоятельно рекомендую вам заменить свои материалы на NHibenrate 3.0.Он «почти» на 100% обратно совместим с NHibernate 2.1, и все, что вам нужно изменить, это все session.Linq<TEntity>() на session.Query<TEntity>().

Если это все еще не работает, вы можете попробовать u.Membership.Any(...) илиu.Membership.First(...) вместо u.Membership.Single(...) в условии where.

Если это не помогло, попробуйте отменить запрос.Сделайте запрос на Membership и выберите membership.User.

CurrentMembership не будет работать, поскольку он не сопоставлен.

...