簡體   English   中英

流暢的NHibernate 3表關系,不包含主鍵和外鍵

[英]Fluent NHibernate 3 table relation without primary and foreign keys

背景資料

我有以下要與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
)

播放器的屏幕名稱可以是電子郵件地址(“ foo@bar.com”),Twitter屏幕名稱(“ @FooBar”),Skype屏幕名稱(“ foo.bar”)或類似的名稱。 使用Fluent NHibernate映射Player的前三個屬性非常容易:

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屬性比較難,因為我必須從兩個不能更改的舊表中獲取該信息,並且必須以只讀方式訪問(不允許插入,更新或刪除):

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

只能取消訂閱電子郵件播放器,因此其他類型的播放器在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.EmailAddress與Player.AddressIdentifier匹配,但是我很難弄清楚如何使用Fluent NHibernate做到這一點。

我已經查看了多個表的Join,但是我發現的所有示例僅處理2個表,而不是3個:

  1. 使用Fluent NHibernate加入表格
  2. 流利的Nhibernate左加入

一種可能的解決方案是對只讀的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添加一個條件以過濾掉非電子郵件播放器來進一步改善選擇查詢。 另外,除非它在應用程序中的其他地方使用,否則您可以擺脫舊有的類和映射。

為了補充Denis的答案 ,我只想添加一些有關Hibernate文檔中屬性公式如何工作的文檔

公式(可選):一個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。 如果不想使用該屬性,也可以使用嵌套的映射元素。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM