Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fluent NHibernate "Could not resolve property"

I have read a lot of the questions about that same error but none since to match my exact problem. I'm trying to access the property of an object, itself part of a root object, using Fluent NHibernate. Some answers say I need to use projections, others that I need to use join, and I think it should work through lazy loading.

Here are my two classes along with the Fluent mappings:

Artist class

public class Artist
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    public virtual IList<Album> Albums { get; set; }
    public virtual string MusicBrainzId { get; set; }
    public virtual string TheAudioDbId { get; set; }

    public Artist() { }
}

public class ArtistMap : ClassMap<Artist>
{
    public ArtistMap()
    {
        LazyLoad();
        Id(a => a.Id);
        Map(a => a.Name).Index("Name");
        HasMany(a => a.Albums)
            .Cascade.All();
        Map(a => a.MusicBrainzId);
        Map(a => a.TheAudioDbId);
    }
}

Album class

public class Album
{
    public virtual int Id { get; set; }
    public virtual Artist Artist { get; set; }
    public virtual string Name { get; set; }
    public virtual IList<Track> Tracks { get; set; }
    public virtual DateTime ReleaseDate { get; set; }
    public virtual string TheAudioDbId { get; set; }
    public virtual string MusicBrainzId { get; set; }

    public Album() { }
}

public class AlbumMap : ClassMap<Album>
{
    public AlbumMap()
    {
        LazyLoad();
        Id(a => a.Id);
        References(a => a.Artist)
            .Cascade.All();
        Map(a => a.Name).Index("Name");
        HasMany(a => a.Tracks)
            .Cascade.All();
        Map(a => a.ReleaseDate);
        Map(a => a.TheAudioDbId);
        Map(a => a.MusicBrainzId);
    }
}

And the error happens when this code is interpreted:

var riAlbum = session.QueryOver<Album>()
                .Where(x => x.Name == albumName && x.Artist.Name == artist)
                .List().FirstOrDefault();

The error happens when Fluent NHibernate tries to resolve the x.Artist.Name value:

{"could not resolve property: Artist.Name of: Album"}

What would be the correct way of doing this?

like image 840
Astaar Avatar asked Dec 17 '14 14:12

Astaar


2 Answers

You have to think of your QueryOver query as (nearly) directly translating into SQL. With this in mind, imagine this SQL query:

select
    Album.*
from
    Album
where
    Album.Name = 'SomeAlbumName' and
    Album.Artist.Name = 'SomeArtistName'

This won't work because you can't access a related table's properties like that in a SQL statement. You need to create a join from Album to Artist and then use a Where clause:

var riAlbum = 
    session.QueryOver<Album>()
               .Where(al => al.Name == albumName)
           .JoinQueryOver(al => al.Artist)
               .Where(ar => ar.Name == artistName)
           .List()
           .FirstOrDefault();

Also, since you're using FirstOrDefault, you may want to consider moving that logic to the database end. Currently, you're pulling back every record matching your criteria and then taking the first one. You could use .Take to limit the query to 1 result:

var riAlbum = 
    session.QueryOver<Album>()
               .Where(al => al.Name == albumName)
           .JoinQueryOver(al => al.Artist)
               .Where(ar => ar.Name == artistName)
           .Take(1)
           .SingleOrDefault<Album>();
like image 61
Andrew Whitaker Avatar answered Sep 30 '22 23:09

Andrew Whitaker


Another explanation is that you are missing your mapping of this property or field in a NHibernateClassMapping definition. I came here about why I was getting this error based on the following scenario.

 var query = scheduleRepository.CurrentSession().Query<Schedule>()
                .Where(x => x.ScheduleInfo.StartDate.Date < dateOfRun.Date);

This was giving me a Could Not Resolve Property error for StartDate. This was a head scratcher, since I use this syntax all the time.

My mapping file was the following:

public class ScheduleInfoMapping : NHibernateClassMapping<ScheduleInfo>
    {
        public ScheduleInfoMapping()
        {
            DiscriminateSubClassesOnColumn("Type");
            Map(x => x.Detail).MapAsLongText();
        }
    }

which was missing the StartDate. Changed to:

public class ScheduleInfoMapping : NHibernateClassMapping<ScheduleInfo>
    {
        public ScheduleInfoMapping()
        {
            DiscriminateSubClassesOnColumn("Type");
            Map(x => x.Detail).MapAsLongText();
            Map(x => x.StartDate);
        }
    }

Which resolved the error.

like image 26
gdbj Avatar answered Oct 01 '22 00:10

gdbj