2011-07-05 33 views
3

我想升級舊的CMS來使用NHibernate,並且不能從原始數據庫結構中遏制太多。這是造成問題的位。說我有以下2個表:在運行時映射一對一關係

Articles: 
- Id (PK, Identity) 
- Title 
- Content 

Meta: 
- ArticleId (PK, FK to Articles) 
- Description 
- Keywords 

我已經創建了以下類:

public class Article { 
    public virtual int Id { get; set; } 
    public virtual string Title { get; set; } 
    public virtual string Content { get; set; } 
} 

public class Meta : IComponent { 
    public virtual string Description { get; set; } 
    public virtual string Keywords { get; set; } 
} 

public interface IComponent { 
} 

一般的元通常會被映射爲組件(或以一對一的關係)屬性對文章類。然而,在構建管理員的應用程序中,可以啓用/禁用適用於文章的組件。另外,我希望他們擴展應用程序以添加他們自己的組件,而無需觸及Article類。

由於他們的原因,我不能添加屬性對文章類。現在,在我的代碼理想我想能夠說:

var articles = session.Query<Article>() 
    .Fetch(a = a.Component<Meta>()) 
    .Where(a => a.Component<Meta>().Keywords.Contains("Some Word")) 
    .ToList(); 

// This wouldn't generate an extra SQL statement 
var keywords = articles[0].Component<Meta>().Keywords; 

這將生成的SQL語句(或類似):

SELECT * FROM文章INNER JOIN元ON Articles.Id =元.ArticleId WHERE Meta.Keywords LIKE'%Some Word%'

是否可以映射Component方法,以便它進行內部聯接以獲取元。這個概念看起來很簡單,但我從頭開始並不知道。我真的很感激幫助。

謝謝

+0

請問,這是什麼意思「...管理員可以啓用/禁用組件...」? –

回答

0

有鑑於此:

public class Article 
{ 
    public virtual int ArticleId { get; set; } 
    public virtual string Title { get; set; } 
    public virtual string Content { get; set; } 
} 


public class Meta : IComponent 
{ 
    public virtual Article Article { get; set; } 

    public virtual int MetaId { get; set; } 
    public virtual string Description { get; set; } 
    public virtual string Keywords { get; set; } 
} 

AFAIK,你不能取東西,不是一個實體的一部分。因此,從您的示例中,無法從Article實體獲取Meta。

所以,如果你想獲取文章的其他信息,你只需要加入文章給他們,然後投射在你的LINQ的,例如完整數據:

var articles = 
     from a in s.Query<Article>() 
     join m in s.Query<Meta>() on a equals m.Article 
     where m.Keywords.Contains("Some Word") 
     select new { a, m }; 

foreach(var x in articles) 
    Console.WriteLine("{0} {1}", x.a.Title, x.m.Description); 

結果查詢:

select * 
from [Article] article0_, [Meta] meta1_ 
where meta1_.ArticleId = article0_.ArticleId 
    and meta1_.Keywords like '%Some Word%' 

另一種方法,從Meta開始,然後獲取文章;上查詢,這將立即投身條,即沒有延遲加載:

var artB = 
     from m in s.Query<Meta>().Fetch(x => x.Article) 
     where m.Keywords.Contains("Some Word") 
     select m; 

foreach (var x in artB) 
    Console.WriteLine("{0} {1}", x.Article.Title, x.Description); 

結果查詢:

select * 
from [Meta] meta0_ 
left outer join [Article] article1_ on meta0_.ArticleId = article1_.ArticleId 
where meta0_.Keywords like '%Some Word%' 

爲了讓只有一個多彩的文章,把一個獨特的元的參考:

create table Article 
(
ArticleId int identity(1,1) not null primary key, 
Title varchar(100) not null, 
Content varchar(100) not null 
); 

create table Meta 
(
    -- this prevents an Article having two Meta 
ArticleId int not null references Article(ArticleId) unique, 

MetaId int identity(1,1) not null primary key, 

Description varchar(100) not null, 
Keywords varchar(100) not null 
); 

insert into Article(Title,Content) values('Great','Yeah') 

insert into Meta(ArticleId, Description, Keywords) values(1,'Oh','Some Word'); 
+0

嗨,謝謝你的回答。第二個選項給了我強大的輸入,但如果我有另一個組件說Meta2然後它下降。我喜歡第一種方法的想法(linq查詢很簡單,並允許我將連接添加到其他組件)。然而,它確實需要比我理想的更多的工作,因爲我必須爲視圖創建一個額外的模型來使其強制輸入。如果有一種方法,我可以說article.Component ().Description(注意文章類/映射可以相應地修改),這將是偉大的。如果沒有,那麼無論如何都歡呼你的幫助。 – nfplee

+0

不錯的想法:-)但是如果有人會在Linq-to-NH中做到這一點,那麼這就不夠了:因爲投影需要一個別名(在設計時評估編譯器),所以挑選,這將是API'Fetch(a => new {art = a,meta = a.Component ()})''。如果他們能夠適應這個想法,嘗試從NHibernate發送電子郵件。 –

+0

好的會的。歡呼你的幫助。 – nfplee

0

在你的NHibernate映射文件中,你可以指定獲取類型。一對一的XML規範位於NHibernate Documentation。請注意,編號5有一個「加入」和「選擇」的選項,它默認爲選擇。

+0

這是如何幫助我映射組件()? – nfplee

+0

xml確定表間映射的細節。組件只是您的對象中的一種類型。您需要將一個屬性放入名爲元組的元類型元件的文檔類中,然後在該配置XML中定義該屬性和元(作爲一對一)之間的關係。 – Zoidberg

+0

仍然有點困惑。您能否以一個例子提供更詳細的答案? – nfplee

0

下面的解決方案會引起您的興趣嗎?

您可以對組件進行受保護的映射,並從此公共泛型方法訪問這些映射。

這樣你就可以選擇急加載/延遲加載你的組件。

public class Article 
{ 
    protected virtual ICollection<IComponent> Components { get; set; } 

    public virtual T Component<T>() where T : IComponent 
    { 
     return Components.FirstOrDefault(c=>c.Type==typeof(T)); 
    } 
} 
+0

嗨,歡呼,這看起來很有希望。我不太清楚我將如何映射組件。我的猜測是我需要在我的數據庫中有一張表來說明哪些組件適用於文章。請讓我知道你的想法。謝謝 – nfplee