2011-03-05 47 views
7

我有一個應用程序女巫使用NHibernate作爲ORM。我有一個持久化類:NHibernate - 從sql函數返回複雜的對象

public class Match : IEntity 
{ 
    public virtual int ID { get; set; } 
    public virtual string Word { get; set; } 
    public virtual int WordIntervalBeginning { get; set; } 
    public virtual int WordIntervalEnding { get; set; } 
} 

,我必須在服務器端的SQL函數:

CREATE FUNCTION ftMatchTest 
() 
RETURNS TABLE 
AS 
RETURN 
(
    SELECT mt1.*, mt2.*, 
    CASE WHEN mt1.Word = mt2.Word THEN 1 ELSE 0 END AS sc 
    FROM 
     dbo.tMatchesTest mt1, dbo.tMatchesTest mt2 
) 

我希望能夠調用此函數,結果從它映射到下面的類

public class FResult 
{ 
    public Match Match1 { get; set; } 
    public Match Match2 { get; set; } 
    public int sc { get; set; } 
} 

NHibernate 3.0能做到嗎?用FluentNHibernate可以做到嗎?
在此先感謝!

已更新
我將匹配類映射到tMatchesTest表中。 tMatchesTest表
結構爲:

CREATE TABLE [dbo].[tMatchesTest](
    [ID] [int] IDENTITY(1,1) NOT NULL, 
    [Word] [varchar](50) NOT NULL, 
    [WordIntervalBeginning] [int] NOT NULL, 
    [WordIntervalEnding] [int] NOT NULL, 
CONSTRAINT [PK_tMatchesTest] PRIMARY KEY CLUSTERED 
(
    [ID] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 

UPDATED2
我對我自己找到了解決辦法:
1.創建這樣

<?xml version="1.0" encoding="utf-8" ?> 

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" 
        namespace=" ConsoleApplication8.Domain.Entities" 
        assembly="ConsoleApplication8"> 

    <resultset name="fresult-resset"> 
    <return alias="Match1" class="Match"/> 
    <return alias="Match2" class="Match"/> 
    <return-scalar column="sc" type="int"/> 
    </resultset> 


    <sql-query name="getfresult" resultset-ref="fresult-resset"> 
    SELECT {Match1.*}, {Match2.*}, 
    CASE WHEN Match1.Word = Match2.Word THEN 1 ELSE 0 END sc 
    FROM dbo.tMatchesTest Match1, dbo.tMatchesTest Match2 
    </sql-query> 

</hibernate-mapping> 

命名查詢和執行這樣的查詢:

Session.GetNamedQuery("getfresult") 
       .SetResultTransformer(new AliasToBeanResultTransformer(typeof(FResult))) 
       .List<FResult>(); 

這是迄今爲止我發現的最簡單,最簡單的方式來執行任務。

+0

你可以發佈tMatchesTest表的結構嗎? – 2011-03-05 10:44:50

+0

我在原文中添加了此表的結構。 – StuffHappens 2011-03-05 10:49:05

+0

是SQL函數的例子代碼?它的內容會更復雜嗎?爲什麼依靠實際查詢功能? – Jaguar 2011-03-10 14:52:40

回答

1

IResultTransformer用於將查詢結果轉換爲應用程序可見類型。

此外,將SQL函數調用映射爲named SQL query將提供更乾淨的代碼。

var list = Session.GetNamedQuery("ftMatchTest") 
    .SetResultTransformer(new AliasToFResultTransformer()) 
    .List<FResult>(); 

由於我們有一個多表結果,AliasToBeanResultTransformer不是直接可用的。相反,我們將繼承它並將結果轉換爲所需的類型。

public class AliasToFResultTransformer : AliasToBeanResultTransformer 
{ 
    public AliasToFResultTransformer() : base(typeof(FMatches)) {} 

    object IResultTransformer.TransformTuple(object[] tuple, string[] aliases) 
    { 
     FMatches fm = base.TransformTuple(tuple, aliases) as FMatches; 

     return fm.ToFResult(); 
    } 

    public class FMatches 
    { 
     public int sc { get; set; } 
     public virtual int Mt1ID { get; set; } 
     public virtual string Mt1Word { get; set; } 
     public virtual int Mt1WordIntervalBeginning { get; set; } 
     public virtual int Mt1WordIntervalEnding { get; set; } 
     public virtual int Mt2ID { get; set; } 
     public virtual string Mt2Word { get; set; } 
     public virtual int Mt2WordIntervalBeginning { get; set; } 
     public virtual int Mt2WordIntervalEnding { get; set; } 

     public FResult ToFResult() 
     { 
      return new FResult { 
       sc = this.sc, 
       Match1 = new Match { 
        Id = this.Mt1Id, 
        Word = this.Mt1Word, 
        WordIntervalBeginning = this.Mt1WordIntervalBeginning, 
        WordIntervalEnding = this.Mt1WordIntervalEnding 
       }, 
       Match2 = new Match { 
        Id = this.Mt2Id, 
        Word = this.Mt2Word, 
        WordIntervalBeginning = this.Mt2WordIntervalBeginning, 
        WordIntervalEnding = this.Mt2WordIntervalEnding 
       } 
      } 
     } 
    } 
} 
0

我不確定這是否適合我們,但您始終可以使用設置返回類型的標識方法。查詢將類似於如下:

Session.CreateSqlQuery(selectStatement).AddEntity(typeof(FResult)).SetString(variableNameIfAny,value).List<FResult>(); 

希望你能得到自己的選擇查詢..只是看到NHibernate的建立燒成這樣的查詢,並檢查使用NHibernate分析器的SQL查詢。

希望這有助於

+0

當我嘗試這樣做時,我得到以下例外'沒有persister爲:ConsoleApplication8.Domain.Entities.FResult' – StuffHappens 2011-03-10 07:28:24

+0

是因爲AddEntity只適用於映射的類 – Jaguar 2011-03-10 14:57:00

+0

我知道他有一個未映射的實體 – Baz1nga 2011-03-12 18:37:28

0

嗯,我能想到的,可能工作的唯一辦法是這樣的:

你的函數映射到一個視圖,讓我們將其命名爲FResult這將只有3列:

[mt1Id, mt2Id, sc] 

現在,您可以在該視圖上映射實體,然後將其映射到實體FResult,合成編號爲[many-to-one{mt1Id}, many-to-one{mt2Id}],並具有HQL和條件的所有花樣或哨子,或者如果您對所有這些和只是想要一個功能,這應該工作,但要記住,你仍然只輸出實體的ID,並從功能的結果值:

var result = Session.CreateSqlQuery(
    @"select {m1.*}, {m2.*}, ft.sc 
     from dbo.ftMatchTest ft, Match m1, Match m2 
     where m1.Id = ft.mt1Id and m2.Id = ft.mt2Id") 
     .AddEntity("m1",typeof(Match)) 
     .AddEntity("m2",typeof(Match)) 
     .AddScalar("sc", NHibernateUtil.BlaBla) 
     .List(); 

請注意,我「一株」功能直接,但我寫的查詢,同時思考一個觀點,所以你可能要修改SQL的功能

現在,結果是對象的ArrayList [],其中的對象[0]和對象[1]水合Match對象和對象[2]是sc值

在這一點上,如果它絕對必要的話,你可以構造一個FResult對象和應用結果,因爲FResult類不是一個完全映射類NHibernate是有限的,它可以使用它(使其輸出IList<FResult>直接)。

1

我會用動態實例,就像這樣:

CREATE FUNCTION ftMatchTest 
() 
RETURNS TABLE 
AS 
RETURN 
(
    -- select each column 
    SELECT mt1.ID ID1, mt2.ID ID2, <etc> 
    CASE WHEN mt1.Word = mt2.Word THEN 1 ELSE 0 END AS sc 
    FROM 
     dbo.tMatchesTest mt1, dbo.tMatchesTest mt2 
) 

然後寫在構造函數您的報告類:

public class FResult 
{ 
    public FResult(int id1, int id2, ..., int sc) 
    { 
     Match1 = new Match(id1, ...); 
     Match2 = new Match(id2, ...); 
     this.sc = sc; 
    } 

    public Match Match1 { get; set; } 
    public Match Match2 { get; set; } 
    public int sc { get; set; } 
} 

並運行查詢...

var result = Session.CreateSqlQuery(
    @"select new FResult(ft.ID1, ft.ID2, ..., ft.sc) 
    from dbo.ftMatchTest ft") 
0

一種可能的解決方案是創建一個視圖而不是函數(或一個調用該函數,如果所需的功能):

CREATE VIEW [MatchTestResults] 
AS 
SELECT mt1.*, 
     mt2.*, 
     CASE WHEN mt1.Word = mt2.Word THEN 1 ELSE 0 END AS sc 
FROM 
    dbo.tMatchesTest mt1, 
    dbo.tMatchesTest mt2 

隨着視圖中,可以在映射它NHibernate就像你會映射一張表一樣。如果NHibernate嘗試將更新提交給對象,SQL Server將會抱怨,顯然,除非你想創建INSTEAD OF觸發器。

+0

如果我需要一個帶參數的函數。此解決方案不起作用。謝謝你的回答! – StuffHappens 2011-03-14 10:00:47