我有简单的用户实体:

public class User
{
    public virtual int Id { get; set; }
    public virtual DateTime CreationDate { get; set; }
    public virtual DateTime ModifiedDate { get; set; }

    public virtual string Email { get; set; }
    public virtual string Name { get; set; }

    public virtual IList<Phone> Phones { get; set; }
}

public class Phone
{
    public virtual string CountryCode { get; set; }
    public virtual string Code { get; set; }
    public virtual string Number { get; set; }
    public virtual string Comment { get; set; }
}


我的映射定义为:

public class UserMap : ClassMap<User>
{
    public UserMap ()
    {
        this.Table ("Users");

        this.Id (x => x.Id).CustomSqlType ("bigint").GeneratedBy.HiLo ("1000");
        this.Map (x => x.CreationDate);
        this.Map (x => x.ModifiedDate).Column ("LastUpdatedDate");
        this.Map (x => x.Email).Length (255).Not.Nullable ().Unique ();
        this.Map (x => x.Name).Column ("UserName").Length (255);

        this.HasMany (x => x.Phones).Inverse ();
    }
}

public class PhoneMap : ClassMap<Phone>
{
    public PhoneMap ()
    {
        this.Table ("Phones");

        this.Id ().GeneratedBy.Identity ();
        this.Map (x => x.CountryCode).Length (5);
        this.Map (x => x.Code).Length (10);
        this.Map (x => x.Number).Length (50).Not.Nullable ();
        this.Map (x => x.Comment).Length (255);
    }
}


此处的其他约定:

PrimaryKey.Name.Is (x => "Id"),
ForeignKey.EndsWith ("Id"),
DefaultAccess.Property (),
DefaultCascade.All ()


我需要选择“电话”排名前100位的用户,且其名称以“ A”开头。但是我需要在其中装入带有电话的用户对象。

所以我做这个查询:

var users =
(
    from user in session.Query<User> ()
    where
        user.Name.StartsWith ("a")
        &&
        user.Phones.Any ()
    select user
)
    .Fetch (x => x.Phones)
    .Take (100)
    .ToArray ();


而且我只有72位用户。

为什么?好吧,因为NHibernate使用左外部联接生成单个TOP N选择,并且SQL会为同一用户实体返回几条记录,因为某些用户确实拥有一部以上的电话。但这一切都与TOP N有关-因此,我获得了100条加入电话的用户的记录,但是其中只有72条是唯一的实体。

有适当的方法吗?

最佳答案

您必须将查询拆分为子选择。内部subselect应该执行分页而外部应该进行抓取:

var top100users =
(
    from user in session.Query<User>()
    where user.Name.StartsWith("a") &&
          user.Phones.Any()
    select user
)
.Take(100);

var users =
(
    from user in session.Query<User>()
    where top100users.Contains(user)
    select user
)
.Fetch (x => x.Phones)
.ToArray();


这将生成单个sql查询,其行为将与您期望的一样。

09-04 16:25
查看更多