Nhibernate - 查询与Linq的一对多关系

时间:2011-01-04 17:19:39

标签: nhibernate fluent-nhibernate linq-to-nhibernate

我想查询实体上的一对多关系。为了帮助进一步解释我的问题,想象一下我的应用程序有以下实体:

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属性所做的那样)。除了映射字符串,整数和布尔值之外,我看不出如何使用公式映射。接下来我试着说:

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

但是这引发了错误:

“对象引用未设置为对象的实例。”

我知道我可以直接查询这个会员资格但我已经用这个作为我在很多地方做的事情的一个例子。任何人都可以建议一种映射CurrentMembership属性的替代方法,它允许我使用Linq查询它。请注意,我需要最佳性能,因此转换为列表并在内存中工作是不够的。

我很感激帮助。感谢

1 个答案:

答案 0 :(得分:0)

您正在使用NHibernateContrib中用于NHibernate 2.1的旧LINQ提供程序。 该提供商不再受支持,也没有任何积极的努力。

NHibernate 3.0语法内置的LINQ提供程序是session.Query<TEntity>()而不是session.Linq<TEntity>()

现在NHibernate 3.0已经发布了,所以,如果你过去遇到过问题,那么它们很可能已经解决了。我使用它们进行繁重的查询,新的查询满足了很多场景 也许最好是获得最新的主干源并使用它。

我强烈建议你用NHibenrate 3.0替换你的东西。它与NHibernate 2.1“几乎”100%向后兼容,您需要更改的全部是session.Linq<TEntity>()session.Query<TEntity>()

如果仍然无效,您可以在u.Membership.Any(...)条件下尝试u.Membership.First(...)u.Membership.Single(...)而不是where

如果仍然无效,请尝试撤消查询。查询Membership并选择membership.User

CurrentMembership无效,因为它未映射。