Brant
Brant

Reputation: 15334

Why does NHibernate's LINQ provider generate invalid T-SQL for a GroupBy()?

I'm trying to do what seems like a simple query for the number of Products produced by each Manufacturer, but NHibernate isn't generating T-SQL that MS SQL Server finds valid.

session.Query<Product>()
    .GroupBy(p => p.Manufacturer)
    .Select(grp => new {Mftr = grp.Key.Name, ProductCount = grp.Count()})
    .ToList();

This seems dead simple, but the SQL statement that NHibernate generates doesn't include all the necessary column names, so it fails when running against a SQL Server 2008 or SQL Server CE database. If I point the same code to an in-memory SQLite database, it works fine.

More information is below, and I also created a small console application that demonstrates my problem. How do I fix this problem?


Generated SQL

select manufactur1_.Id,
    cast(count(*) as INT), 
    manufactur1_.Id, 
    manufactur1_.Name 
from "Product" product0_ 
    left outer join "Manufacturer" manufactur1_ 
    on product0_.Manufacturer_id=manufactur1_.Id 
group by manufactur1_.Id   -- Where's manufactur1_.Name?

Entities

public class Product {
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    public virtual Manufacturer Manufacturer { get; set; }
}
public class Manufacturer {
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
}

FNH Mappings

public class ProductMap : ClassMap<Product> {
    public ProductMap() {
        Id(x => x.Id).GeneratedBy.HiLo("1");
        Map(x => x.Name);
        References(x => x.Manufacturer).Cascade.SaveUpdate().Not.Nullable();
    }
}

public class ManufacturerMap : ClassMap<Manufacturer> {
    public ManufacturerMap() {
        Id(x => x.Id) .GeneratedBy.HiLo("1");
        Map(x => x.Name);
    }
}

Upvotes: 2

Views: 369

Answers (1)

dotjoe
dotjoe

Reputation: 26940

Here's a QueryOver version...

//alias variables
Manufacturer m = null;
ManufacturerProducts dto = null;

var result = Session.QueryOver<Product>
    .Left.JoinAlias(x => x.Manufacturer, () => m)
    .SelectList(list => list
        .SelectGroup(() => m.Id).WithAlias(() => dto.Id)
        .SelectGroup(() => m.Name).WithAlias(() => dto.Name)
        .SelectCount(x => x.Id).WithAlias(() => dto.ProductCount))
    .TransformUsing(Transformers.AliasToBean<ManufacturerProducts>())
    .List<ManufacturerProducts>();

Upvotes: 2

Related Questions