簡體   English   中英

FluentNhibernate公式映射,帶有來自聯接表的參數

[英]FluentNhibernate Formula mapping with parameters from joined table

我對FluentNhibernate公式映射有問題。 我需要在公式中使用聯接表中的列。

在以下三個表上顯示了問題: 城市,人,地址

class Person {
    int PersonId { get; set; }

    int AddressId { get; set; }  

    Address PersonAddress { get; set; }

    string CityName { get; set; }
}

class Address {       
    int AddressId { get; set; }

    string Street { get; set; }
}

class AddressMap<Address> { 
    Id(x => x.AddressId, "ADDRESS_ID");

    Map(x => x.Street, "STREET");
}


class PersonMap<Person> {
    Id(x => x.Id, "PERSON_ID");

    References(x => x.PersonAddress).Column("ADDRESS_ID);

    Map(x => x.CityName).Formula("select Name from City c where c.street = STREET"); 
    // Doesn't work, STREET is a part of the joined table !
}

任何想法如何正確編寫公式映射? 當我使用NHibernate會生成的值重寫映射時,一切都會起作用,盡管如此,這是一個非常骯臟的解決方案:

Map(x => x.CityName).Formula("select Name from City c where c.street = address1_.STREET"); 
// Works !!

將不勝感激!

NHibernate中沒有直接的方法來支持另一個聯接表的別名。 為什么?

因為連接表根本沒有要連接的一部分

考慮延遲加載的地址-即不是SELECT的一部分,或者一些沒有地址表的投影。

公式旨在以一種更聰明的方式來訪問當前表中的數據。 或如何創建一些獨立的子選擇子查詢子查詢並傳遞當前id作為參考過濾器。

例如,在Ayende的NHibernate屬性Mapping中 ,我們可以看到:

<property name="CountOfPosts"
    formula="(select count(*) from Posts where Posts.Id = Id)"/>

像這樣生成SELECT:

SELECT ...
       // the injected 'Id' is from current table
       (select count(*) from Posts where Posts.Id = this_.Id) 
FROM [MainTable] this_ // the alias of current table

建議: City或城市名稱可能只是另一個引用(如果不是直接作為地址的字符串屬性)。 它將使我們能夠非常輕松地使用它(選擇,投影,過濾,排序),並且我們將不必依賴某些“隱藏的,硬編碼的”映射。 它將是干凈的模型:

Person.Address.City.Name

RadimKöhler提供的大多數一般性提示都是正確的,但是關於公式公式化的最初問題-NH(至少> = 5,我不知道較舊的公式如何)應該能夠解決這種情況。

首先,您的嘗試將失敗,因為在公式中,任何引用當前主實體以外的內容的列名都必須以別名作為前綴。 否則,NH將假定列名稱引用當前的主要實體。

例如,您最初的嘗試是:

Map(x => x.CityName).Formula("select Name from City c where c.street = STREET"); 
                                     ^ fault        ^CEE    ^CEE       ^fault

請注意如何在street上添加c前綴,以區分哪個street來自城市,哪個不是城市。 NHibernate將檢測到此類前綴,並假定所有帶前綴的列都綁定到sql文本中指定的表。 因此,將假定c.street不重要。 但是, STREETName沒有前綴。 NH將假定它們來自主要實體,即您要為其定義映射的Person。 有時這可能會產生有趣的結果,但更有可能的是,“人”表上沒有“ Name或“ Street列,因此rdbms會導致錯誤。

要解決此問題,您應該具有以下內容:

Map(x => x.CityName).Formula("select c.Name from City c where c.street = a.STREET");
                                     ^CEE                                ^AYE

當然,現在另一個錯誤將表明前綴a是未知的。 當然,我們沒有在任何地方定義它,因為我們有PERSON和CITY並且中間的ADDRESS在sql查詢中完全被省略了。

現在,看看這個:

Map(x => x.CityName)
    .Formula(@"
        select c.Name
        from City c
        where c.street =
        (    select a.Street
             from Address a
             where a.address_id = address_id
        )");                      ^
                                  ^ no prefix!

由於內部address_id沒有前綴,因此NH將假定它來自Person。 大。 沒有其他無前綴的列,因此所有其他列都將被忽略,並假定綁定到SQL文本本身中定義的范圍。

因此,內部子查詢將選擇基於Person.AddressID的地址,並從中選擇街道。 希望這只是一條街道,因為我們通過ID匹配地址。 找到街道后,外部子查詢將使用它來匹配城市。

我們也可以將公式寫為

        select c.Name
        from Address a
        inner join City c no c.street = a.street
        where a.address_id = address_id

具有相同的效果和可能不同的性能。

需要注意的一件事是,當您編寫子查詢公式或在子查詢中編寫where foo = (select x from...)時, 必須確保子查詢始終返回零或一個結果。 不能兩個或兩個以上。 許多RDBMS將這種情況視為錯誤。 如果進行此查詢,則多個城市中可能會出現相同的street名稱,因此您將失敗的可能性很高,只是因為您將地址與街道進行了匹配。

暫無
暫無

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

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