简体   繁体   English

带有NHibernate的QueryOver多个表

[英]QueryOver multiple tables with NHibernate

I'm trying to left join multiple tables and project some columns that result from this join onto a new entity, and then taking a few records from this result from my database. 我试图离开联接多个表,并将由此联接产生的一些列投影到新实体上,然后从数据库中获得该结果的一些记录。 I've taken a look on a few similar questions here on SF, but I'm not managing to assemble all of those parts into a piece of code that works. 在SF上,我已经研究了一些类似的问题,但是我没有设法将所有这些部分组合成有效的代码。

Here is the query I'm trying to generate with NHibernate: 这是我尝试使用NHibernate生成的查询:

select * from 
( select LOC_Key.KeyName, LOC_Translation.TranslationString, LOC_Translation.Comments
  from LOC_Key
  left join LOC_Translation
  on LOC_Key.ID = LOC_Translation.KeyID and LOC_Translation.LanguageID = 6
  order by LOC_Key.KeyName 
) as keyTable 
limit 0,100

I have three entities here, Key, Translation and Language. 我在这里有三个实体,即键,翻译和语言。 A Key is a unique string identifier for different translations of a same word in different languages. 关键字是一个唯一的字符串标识符,用于同一单词在不同语言中的不同翻译。 I want to show the first n keys in alphabetical order for a language, but I want all keys listed, not only the ones that are translated (that's why I'm using a left join). 我想按字母顺序显示一种语言的前n个键,但我希望列出所有键,而不仅仅是已翻译的键(这就是为什么我使用左联接)。

I took a look at QueryOver<> , Select() method and List<object[]>() method but I can't even manage to have a code that compiles in the first place. 我看了一下QueryOver<>Select()方法和List<object[]>()方法,但是我什至无法管理要首先编译的代码。

I could use C# linq after getting all records from the tables Key and Translation, having something like this: 从表Key和Translation获得所有记录后,我可以使用C#linq,如下所示:

IEnumerable<string> k = RepositoryKey.GetLimits( offset, size ).Select( x => x.KeyName );

IEnumerable<TranslationDescriptor> t = RepositoryTranslation.GetAllWhere( x => x.LanguageID.LanguageCode == language && k.Contains ( x.KeyID.KeyName ) ).ToList().ConvertAll( new Converter<Translation, TranslationDescriptor>( ( x ) => { return new TranslationDescriptor { LanguageCode = x.LanguageID.LanguageCode, KeyName = x.KeyID.KeyName, Comments = x.Comments, TranslationString = x.TranslationString }; } ) );

var q = from key in k
        join trl in t on key equals trl.KeyName into temp
        from tr in temp.DefaultIfEmpty()
        select new TranslationDescriptor { KeyName = key, LanguageCode = language, Comments = ( tr == null ) ? string.Empty : tr.Comments, TranslationString = ( tr == null ) ? string.Empty : tr.TranslationString };

However, that's very slow. 但是,这非常慢。 By the way, my implementation for GetLimits and GetAllWhere is: 顺便说一下,我对GetLimits和GetAllWhere的实现是:

public IEnumerable<T> GetAllWhere(Func<T, bool> func)
{
    var products = Session.Query<T>().Where(func);
    return products;
}

public IEnumerable<T> GetLimits(int offset, int size)
{
    return Session.CreateCriteria(typeof(T)).SetFirstResult(offset).SetMaxResults(size).List<T>();
}

Thank you for your help! 谢谢您的帮助!

Bruno 布鲁诺

I'm guessing a little bit at your entities and mappings, but the following might help you get ideas. 我在猜测您的实体和映射,但以下内容可能会帮助您获得想法。 It joins Key to Translation with a left outer join, then projects the results to a new DTO object. 它使用左外部连接将“ Translation Key连接起来,然后将结果投影到新的DTO对象。

[Test]
public void LeftOuterProjection()
{
    using (var s = OpenSession())
    using (var t = s.BeginTransaction())
    {
        // Set up aliases to use in the queryover.
        KeyDTO dtoAlias = null;
        Key keyAlias = null;
        Translation translationAlias = null;

        var results = s.QueryOver<Key>(() => keyAlias)
            .JoinAlias(k => k.Translations, () => translationAlias, JoinType.LeftOuterJoin)
            .Where(() => translationAlias.LanguageId == 6)
            .OrderBy(() => keyAlias.KeyName).Asc
            .Select(Projections.Property(() => keyAlias.KeyName).WithAlias(() => dtoAlias.KeyName),
                    Projections.Property(() => translationAlias.TranslationString).WithAlias(() => dtoAlias.TranslationString),
                    Projections.Property(() => translationAlias.Comments).WithAlias(() => dtoAlias.Comments))
            .TransformUsing(Transformers.AliasToBean<KeyDTO>())
            .List<KeyDTO>();
    }
}

public class KeyDTO
{
    public string KeyName { get; set; }
    public string TranslationString { get; set; }
    public string Comments { get; set; }
}

public class Key
{
    public int Id { get; set; }
    public string KeyName { get; set; }
    public IList<Translation> Translations { get; set; }
}

public class Translation
{
    public Key Key { get; set; }
    public int LanguageId { get; set; }
    public string TranslationString { get; set; }
    public string Comments { get; set; }
}

The modifications I made to my code following ngm suggestion (thanks!): 我根据ngm建议对代码进行的修改(谢谢!):

Language l = RepositoryLanguage.GetSingleOrDefault(x => x.LanguageCode
== language); 

KeyTranslationDTO dtoAlias = null;  
Key keyAlias = null;  
Translation translationAlias = null; 

var results = RepositoryKey.GetSession()
  .QueryOver<Key>(() => keyAlias)
  .OrderBy(() => keyAlias.KeyName).Asc
  .JoinQueryOver<Translation>( k => k.Translations, () => translationAlias, JoinType.LeftOuterJoin, Restrictions.Where( () => translationAlias.LanguageID == l ) )   
  .Select(Projections.Property(() => keyAlias.KeyName).WithAlias(() => dtoAlias.KeyName),  
          Projections.Property(() => translationAlias.TranslationString).WithAlias(() => dtoAlias.TranslationString),    
          Projections.Property(() => translationAlias.Comments).WithAlias(() => dtoAlias.Comments))
  .TransformUsing(Transformers.AliasToBean<KeyTranslationDTO>())
  .Skip(index).Take(amount)
  .List<KeyTranslationDTO>();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM