2013-10-01 67 views
2

假設我有一個包含學術論文表的數據庫,並且有一個表明論文是否發表在「主要」期刊上的列(有點像)。我可能想要運行一個查詢來列出每個作者,以及他們是否曾在其中之一發表過。它可能看起來像:NHibernate:CastProjection沒有persister

select author, max(cast(major_journal as INT)) as ever_published 
from AcademicPapers 
group by author; 

很酷!現在我想用NHibernate來做到這一點。切割出查詢的其餘部分,並專注於max(cast(...))的一部分,我想這一點:

Projections.Max<AcademicPaper>( 
    m => Projections.Cast(NHibernateUtil.Int32, Projections.Property("major_journal"))) 
    .WithAlias(() => report.EverPublished) 

然而,當我運行它,我得到一個例外是對我或多或少令人費解:

No persister for: NHibernate.Criterion.CastProjection 

我完全知道我已經錯誤地構造了這個Projection業務,但是我還沒有找到NHibernate的好參考。每次我搜索一個,我只找到StackOverflow。我很樂意爲這個特定的問題找到一個手,或者通過一個關於這裏實際發生的體面寫作的鏈接。

謝謝親切!

+1

我找到了解決我眼前的問題。 'Projections.Max'重載了好幾次,一次重載可以簡單地進行另一次投影,在這種情況下是'Projections.Cast'。這樣所需要的線是這樣的: 'Projections.Max( Projections.Cast(NHibernateUtil.Int32,Projections.Property( 「major_journal」)) .WithAlias(()=> report.EverPublished)' 我的原嘗試使用不必要的複雜版本的'Projections.Max'。 – phil

回答

0

我希望我能正確理解你的問題,所以你只想讓所有的作者至少有一張紙,這個標誌設置爲true,對吧?

爲什麼你不只是使用Linq,它的方式更容易編寫,應該適用於這樣簡單的場景。 我還要你的標誌映射到一個布爾值,所以我想沒有必要做Max運行在所有... 例子:

var authorsWithPublications = session.Query<Paper>() 
    .Select(p => new { Author = p.Author, HasPublished = p.HasPublished }) 
    .Where(p => p.HasPublished == true).ToList(); 

我用這個簡單的場景,讓我知道如果這並未「T匹配您的問題:

實體+映射:一些測試數據的

public class Paper 
{ 
    public virtual int Id { get; set; } 
    public virtual string Author { get; set; } 
    public virtual bool HasPublished { get; set; } 
    public virtual string Description { get; set; } 
    public virtual string Something { get; set; } 
    public virtual string SomethingElse { get; set; } 
} 

public class PaperMap : ClassMap<Paper> 
{ 
    public PaperMap() 
    { 
     Id<int>("Id"); 

     Map(p => p.Author); 
     Map(p => p.HasPublished); 
     Map(p => p.Description); 
     Map(p => p.Something); 
     Map(p => p.SomethingElse); 
    } 
} 

創建和查詢

using (var session = sessionFactory.OpenSession()) 
{ 
    Random r1 = new Random(); 

    for (int i = 0; i < 100; i++) 
    { 
     session.Save(new Paper() 
     { 
      Author = "Author" + i, 
      HasPublished = r1.Next(0, 2) == 0 ? false : true, 
      Description = "Description" +i, 
      Something = "Something" + i, 
      SomethingElse = "something else" + i 
     }); 
    } 
    session.Flush(); 

    var authorsWithPublications = session.Query<Paper>() 
       .Select(p => new { Author = p.Author, HasPublished = p.HasPublished }) 
       .Where(p => p.HasPublished == true).ToList(); 
} 

它實際上返回我到底那些作者......你可以處理這進一步有隻是一個不同的結果...

:編輯開始: 查詢所有的作者與標誌的最大值,它成爲一個有點棘手使用LINQ,下面的LINQ查詢將返回結果:

var authorsWithPublications = session.Query<Paper>() 
       .GroupBy(p => new { Author = p.Author }) 
       .Select(p => new { 
        Author = p.Key, 
        HasPublished = p.Max(c=> c.HasPublished) 
       }) 
       .ToList(); 

但如果c.HasPublished是SqlServer的一個位字段,它會給你的SQL異常最大值是不允許位字段。

試圖將布爾轉換爲int wihtin LINQ的聲明像

...HasPublished = p.Max(c => c.HasPublished == true ? 1 : 0) 

會拋出異常Code supposed to be unreachable,因爲它不是由NHibernate的支持...

我發現拿到第一Linq查詢運行的唯一方法是通過映射中指定一個公式:

Map(p => p.HasPublished).Formula("cast (HasPublished as int)"); 

現在這個公式將適用於所有的select語句,聲明將是這樣的:

select paper0_.Author as col_0_0_, max(cast (paper0_.HasPublished as int)) as col_1_0_ 
from [Paper] paper0_ 
group by paper0_.Author 

反正你已經找到了解決辦法和以下實際執行,而不需要一個公式

相同
var criteria = session.CreateCriteria<Paper>(); 
criteria.SetProjection(
    Projections.Group<Paper>(p=>p.Author), 
    Projections.Max(
     Projections.Cast(NHibernateUtil.Int32, Projections.Property("HasPublished"))) 
    ); 
var result = criteria.List(); 

但也許我們都學到了一些東西;)

+0

我在尋找的東西稍有不同,雖然我毫不懷疑linq方法可能適用於它;我想要返回所有(不同的)作者,然後是0或1,表示它們是否已發佈,我沒有被要求將已發佈和未發佈的作者分爲兩個單獨的查詢,感謝您的回答,我很樂意接受它只要它仍然捕捉到原來的意圖,我還用我找到的解決方案爲原始問題添加了一條評論。不提交答案,因爲我是全新的。) – phil

+0

我真的很感激這樣一個答案的詳細例子,再次感謝。 – phil

+0

@phil我在回答中增加了一些更多的發現,也許對你也有意思 – MichaC

相關問題