开发者

NHibernate 3.0 IQueryable selecting ghost column

I'm getting a strange error when running what appears to be a simple query.

return (from x in session.Query<Contact>()
                .Where(x => x.Id == 10)
               select new ContactIndexViewModel
               {
                   Id = x.Id,
                   Name = x.BasicInfo.FirstName + " " + x.BasicInfo.LastName,
                   Filters = x.Filters
               }).FirstOrDefault();

Is generating the following SQL

select 
    contact0_.[Id] as col_0_0_, 
    contact0_.[BasicInfoFirstName] as col_1_0_, 
    contact0_.[BasicInfoLastName] as col_2_0_, 
    . as col_3_0_,
    filters1_.[Id] as column1_16_, 
    filters1_.Criteria1 as Criteria2_16_, 
    // .. .more filters1_ fields
    filters1_.ContactId as ContactId16_ 
from 
    [MyServer].[dbo].[Contact] contact0_ 
    inner join [MyServer].[dbo].[Filter] filters1_ 
        on contact0_.[Id]=filters1_.ContactId
where
    contact0_.[Id]=@p0

Notice the fourth column being selected. BasicInfo is a component and the select (in the query) includes all the fields defined in the ViewModel.

I am not having any other problems with the Contact or Filter objects in other parts of the application. Contact -> Filter has a one to many relationship.

Any idea's on how to debug or what may cause this?

UPDATE

If I remove the reference to Filters in the select, the problem goes away.

UPDATE Relevant Mappings

Contact

public partial class ContactMap : ClassMap<Contact>
{
    /// <summary>Initializes a new instance of the <see cref="ContactMap"/> class.</summary>
    public ContactMap()
    {
        Table("[MyServer].[dbo].[Contact]");
        OptimisticLock.Version();
        DynamicUpdate();
        LazyLoad();

        Id(x=>x.Id)
            .Access.CamelCaseField(Prefix.Underscore)
            .Column("[Id]")
            .GeneratedBy.Identity();
        Version(x=>x.RecordVersion)
            .Access.CamelCaseField(Prefix.Underscore)
            .Column("[RecordVersion]")
                .CustomSqlType("timestamp")
                .Not.Nullable()
            .UnsavedValue("null")
            .CustomType("BinaryBlob")
            .Generated.Always();
        Map(x=>x.Active).Access.CamelCaseField(Prefix.Underscore);
        // other scalar properties
        Component(x0=>x0.BasicInfo, m0=>
        {
            m0.Map(x1=>x1.FirstName).Column("[BasicInfoFirstName]").Access.CamelCaseField(Prefix.Underscore);
            m0.Map(x1=>x1.LastName).Column("[BasicInfoLastName]").Access.CamelCaseField(Prefix.Underscore);
            // other scalar properties
        });

        // other relationships

        HasMany(x=>x.Searches)
            .Access.CamelCaseField(Prefix.Underscore)
            .Cascade.AllDeleteOrphan()
            .Fetch.Select()
            .Inverse()
            .LazyLoad()
            .KeyColumns.Add("ContactId");           
    } 
} 

Search

public partial class SearchMap : ClassMap<开发者_如何学C;Search>
{
    public SearchMap()
    {
        Table("[MyServer].[dbo].[Search]");
        OptimisticLock.Version();
        DynamicUpdate();
        LazyLoad();

        Id(x=>x.Id)
            .Access.CamelCaseField(Prefix.Underscore)
            .Column("[Id]")
            .GeneratedBy.Identity();
        Map(x=>x.Controller).Not.Nullable().Access.CamelCaseField(Prefix.Underscore);
        Map(x=>x.Module).Not.Nullable().Access.CamelCaseField(Prefix.Underscore);
        Map(x=>x.Name).Column("[Name]").Not.Nullable().Access.CamelCaseField(Prefix.Underscore);

        References(x=>x.Contact)
            .Access.CamelCaseField(Prefix.Underscore)
            .Cascade.All()
            .Fetch.Select()
            .Columns("ContactId");
        HasMany(x=>x.DataFilters)
            .Access.CamelCaseField(Prefix.Underscore)
            .Cascade.AllDeleteOrphan()
            .Fetch.Select()
            .Inverse()
            .LazyLoad()
            .KeyColumns.Add("SearchId");
    } 
} 


Did you map Filters with FetchMode.Join?

By the way, it may be easier to create the ContactIndexViewModel in memory, with the trade off that it fetches too many columns from the database. On the other side, Get doesn't flush the session, which may be performance relevant.

var contact = session.Get<Contact>(10);

return new ContactIndexViewModel
{
     Id = contact.Id,
     Name = contact.BasicInfo.FirstName + " " + contact.BasicInfo.LastName,
     Filters = contact.Filters
};


Your mapping for the table is unusual to me.

Table("[MyServer].[dbo].[Contact]");

Normally the server name is provided during configuration, the schema is stated separately, and the delimiters ("[...]") are set by NHibernate. I would map it as:

Schema("dbo");
Table("Contact");

That may be causing a parsing problem leading to the odd select. If that's not it, then I think it's a bug -- NHibernate should never issue a select without a table alias and column name.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜