web-dev-qa-db-ja.com

流暢なNHibernate「プロパティを解決できませんでした」

私はその同じエラーに関する多くの質問を読みましたが、私の正確な問題に一致するため、何も読んでいません。 Fluent NHibernateを使用して、ルートオブジェクトの一部であるオブジェクトのプロパティにアクセスしようとしています。プロジェクションを使用する必要があるという回答もあれば、joinを使用する必要があると回答する回答もあり、遅延読み込みで機能するはずです。

Fluentマッピングとともに私の2つのクラスを次に示します。

アーティストクラス

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);
    }
}

アルバムクラス

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);
    }
}

そして、このコードが解釈されるとエラーが発生します:

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

Fluent NHibernateがx.Artist.Name値を解決しようとすると、エラーが発生します。

{「プロパティを解決できませんでした:Artist.Name of:Album」}

これを行う正しい方法は何でしょうか?

17
Astaar

QueryOverクエリは、(ほとんど)直接SQLに変換するものと考える必要があります。これを念頭に置いて、次のSQLクエリを想像してください。

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

SQLステートメントではそのような関連テーブルのプロパティにアクセスできないため、これは機能しません。 AlbumからArtistへの結合を作成する必要がありますthenWhere句を使用します:

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

また、FirstOrDefaultを使用しているので、そのロジックをデータベースの最後に移動することを検討してください。現在、基準に一致するすべてのレコードをプルバックして、最初のレコードを取得しています。 .Takeクエリを1つの結果に制限するには:

var riAlbum = 
    session.QueryOver<Album>()
               .Where(al => al.Name == albumName)
           .JoinQueryOver(al => al.Artist)
               .Where(ar => ar.Name == artistName)
           .Take(1)
           .SingleOrDefault<Album>();
32
Andrew Whitaker

もう1つの説明は、NHibernateClassMapping定義でこのプロパティまたはフィールドのマッピングが欠落していることです。次のシナリオに基づいてこのエラーが発生する理由についてここに来ました。

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

これにより、StartDateの「プロパティを解決できませんでした」エラーが発生しました。私はいつもこの構文を使用しているので、これは頭を悩ませるものでした。

私のマッピングファイルは次のとおりです。

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

startDateがありませんでした。変更:

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

エラーを解決しました。

2
gdbj