0

背景情報

NHibernate でマップしたい次のクラスがあります。

public class Player
{
    public virtual int Id { get; set; }
    public virtual Type Type { get; set; }
    public virtual string ScreenName { get; set; }
    public virtual bool Unsubscribed { get; set; }
}

データベース側には、次のテーブルがあります。

-- New table
Player (
    int Id
    int TypeId (not null) -- foreign-key to Type table
    string ScreenName (not null) -- can be an EmailAddress, but not necessarily
)
Type (
    int Id
    string Name -- "Email", "Facebook", etc
)

Player の ScreenName には、電子メール アドレス ("foo@bar.com")、Twitter のスクリーン名 ("@FooBar")、Skype のスクリーン名 ("foo.bar")、またはそのようなものを指定できます。Fluent NHibernate を使用して Player の最初の 3 つのプロパティをマッピングするのは簡単です。

public class PlayerMap : ClassMap<Player>
{
    public PlayerMap()
    {
        Id(x => x.Id);
        Map(x => x.ScreenName)
            .Not.Nullable();
        References(x => x.Type)
            .Column("TypeId")
    }
}

public class TypeMap : ClassMap<Type>
{
    public TypeMap()
    {
        Id(x => x.Id);
        Map(x => x.Name);
    }
}

しかし、Unsubscribed プロパティは、変更できず、読み取り専用 (挿入、更新、または削除が許可されていない) でアクセスする必要がある 2 つの従来のテーブルからその情報を取得する必要があるため、より困難です。

-- Legacy tables, can't change
EmailAddress (
    int Id
    string EmailAddress (not null) -- "foo@bar.com"
)
Unsubscribed (
    int Id
    int EmailAddressId (not null) -- foreign key to EmailAddress table
)

購読を解除できるのは電子メール Player のみであるため、他のタイプの Player は EmailAddress テーブルにも Unsubscribed テーブルにも行がありません。

レガシー テーブルのクラスは次のとおりです。

public class EmailAddress
{
    public virtual int Id { get; set; }
    public virtual string Value { get; set; }
    public virtual IList<Unsubscription> Unsubscriptions{ get; set; }
}

public class Unsubscription
{
    public virtual int Id { get; set; }
    public virtual EmailAddress EmailAddress { get; set; }
}

Fluent マッピングは次のとおりです。

public class EmailAddressMap : ClassMap<EmailAddress>
{
    public EmailAddressMap()
    {
        ReadOnly();
        Id(x => x.Id);
        Map(x => x.Value)
            .Column("EmailAddress")
            .Not.Nullable();
        HasMany(x => x.Unsubscriptions)
            .KeyColumn("EmailAddressId");
    }
}

public class EmailOptOutMap : ClassMap<EmailOptOut>
{
    public EmailOptOutMap()
    {
        ReadOnly();
        Id(x => x.Id);
        References(x => x.EmailAddress)
            .Column("EmailAddressId");
    }
}

問題

私が抱えている問題は、電子メール プレーヤーの購読解除された情報を取得しようとしていることです。

Unsubscribed テーブルを Player テーブルに関連付ける唯一の方法は、EmailAddress.EmailAddress を Player.AddressIdentifier に一致させる中間の EmailAddress テーブルを使用することですが、Fluent NHibernate でこれを行う方法がわかりません。

複数のテーブルの Join を見てきましたが、私が見つけたすべての例では、3 つではなく 2 つのテーブルしか扱っていません。

  1. Fluent NHibernate を使用してテーブルに参加する
  2. Fluent Nibernate が結合を残しました
4

2 に答える 2

1

考えられる解決策の 1 つは、読み取り専用Unsubscribedプロパティの数式を使用して、レガシー テーブルに格納されているデータに基づいて値を動的に設定することです。次のようにマッピングできます。

Map(x => x.Unsubscribed).Formula("(CASE WHEN EXISTS (SELECT EA.Id FROM EmailAddress EA INNER JOIN Unsubscribed ON EA.Id = Unsubscribed.EmailAddressId WHERE EA.EmailAddress = ScreenName) THEN 1 ELSE 0 END)").ReadOnly();

もちろん、メール以外のプレーヤーを除外する TypeId の条件を追加することで、select クエリをさらに改善できます。さらに、アプリの他の場所で使用されていない限り、レガシー クラスとマッピングを取り除くことができます。

于 2012-02-10T22:44:47.230 に答える
0

Denis's answerを補足するために、 Hibernate docsからプロパティ式がどのように機能するかについての追加のドキュメントを追加したかっただけです:

formula (オプション): 計算されたプロパティの値を定義する SQL 式。計算されたプロパティには、独自の列マッピングがありません。

強力な機能は派生プロパティです。これらのプロパティは、定義上、読み取り専用です。プロパティ値はロード時に計算されます。計算を SQL 式として宣言します。これは、インスタンスをロードする SQL クエリの SELECT 句のサブクエリに変換されます。

<property name="totalPrice" formula="( SELECT SUM (li.quantity*p.price) FROM LineItem li, Product p WHERE li.productId = p.productId AND li.customerId = customerId AND li.orderNumber = orderNumber )"/>

特定の列でエイリアスを宣言しないことで、エンティティ テーブルを参照できます。これは、この例では customerId になります。属性を使用したくない場合は、ネストされたマッピング要素を使用することもできます。

于 2014-07-28T07:11:52.800 に答える