2013-02-21 56 views
0

我們應該如何查詢多個一個一對多的關係

我試圖優化我的查詢,需要一些建議。這是查詢一對多關係的首選方式嗎?

我的領域是這樣的:

MeasureSet

/// <summary> 
    /// 
    /// </summary> 
    /// <remarks> 
    /// Tables: none 
    /// </remarks> 
    public class MeasureSet : PersistentEntity 
    { 
     #region Properties 
     /// <summary> 
     /// Gets or sets the code. 
     /// </summary> 
     /// <value> 
     /// The code. 
     /// </value> 
     public virtual string Code { get; set; } 
     /// <summary> 
     /// Gets or sets the description. 
     /// </summary> 
     /// <value> 
     /// The description. 
     /// </value> 
     public virtual string Description { get; set; } 
     /// <summary> 
     /// Gets or sets the measure domains. 
     /// </summary> 
     /// <value> 
     /// The measure domains. 
     /// </value> 
     public virtual IList<MeasureDomain> MeasureDomains { get; protected set; } 
} 

MeasureDomain

/// <summary> 
    /// 
    /// </summary> 
    /// <remarks> 
    /// Tables: domeinen 
    /// </remarks> 
    public class MeasureDomain : PersistentEntity 
    { 
     #region Properties 
     /// <summary> 
     /// Gets or sets the code. 
     /// </summary> 
     /// <value> 
     /// The code. 
     /// </value> 
     public virtual string Code { get; set; } 
     /// <summary> 
     /// Gets or sets the description. 
     /// </summary> 
     /// <value> 
     /// The description. 
     /// </value> 
     public virtual string Description { get; set; } 
     /// <summary> 
     /// Gets or sets the explanation. 
     /// </summary> 
     /// <value> 
     /// The explanation. 
     /// </value> 
     public virtual string Explanation { get; set; } 
     /// <summary> 
     /// Gets or sets the measure set. 
     /// </summary> 
     /// <value> 
     /// The measure set. 
     /// </value> 
     public virtual MeasureSet MeasureSet { get; set; } 
     /// <summary> 
     /// Gets or sets the measure sub domains. 
     /// </summary> 
     /// <value> 
     /// The measure sub domains. 
     /// </value> 
     public virtual IList<MeasureSubDomain> MeasureSubDomains { get; protected set; } 
     /// <summary> 
     /// Gets or sets the audits. 
     /// </summary> 
     /// <value> 
     /// The audits. 
     /// </value> 
     public virtual IList<Audit> Audits { get; protected set; } 
     #endregion 
} 

MeasureSubDomain

/// <summary> 
    /// 
    /// </summary> 
    /// <remarks> 
    /// Tables: subdomeinen, subdomeinenbestanden 
    /// </remarks> 
    public class MeasureSubDomain : PersistentEntity 
    { 
     #region Properties 
     /// <summary> 
     /// Gets or sets the code. 
     /// </summary> 
     /// <value> 
     /// The code. 
     /// </value> 
     public virtual string Code { get; set; } 
     /// <summary> 
     /// Gets or sets the description. 
     /// </summary> 
     /// <value> 
     /// The description. 
     /// </value> 
     public virtual string Description { get; set; } 
     /// <summary> 
     /// Gets or sets the domain. 
     /// </summary> 
     /// <value> 
     /// The domain. 
     /// </value> 
     public virtual MeasureDomain MeasureDomain { get; set; } 
     /// <summary> 
     /// Gets or sets the explanation. 
     /// </summary> 
     /// <value> 
     /// The explanation. 
     /// </value> 
     public virtual string Explanation { get; set; } 
     /// <summary> 
     /// Gets or sets the files. 
     /// </summary> 
     /// <value> 
     /// The files. 
     /// </value> 
     public virtual IList<File> Files { get; protected set; } 
     /// <summary> 
     /// Gets or sets the measure controls. 
     /// </summary> 
     /// <value> 
     /// The measure controls. 
     /// </value> 
     public virtual IList<MeasureControl> MeasureControls { get; protected set; } 
     /// <summary> 
     /// Gets or sets the audits. 
     /// </summary> 
     /// <value> 
     /// The audits. 
     /// </value> 
     public virtual IList<Audit> Audits { get; protected set; } 
} 

我只需要收集子代碼,代碼和描述屬性。目前我使用的查詢是這樣的:

一個一對多查詢

measureSets = LazySessionFactory.CurrentSession.CreateCriteria<MeasureSet>() 
     .Add(Subqueries.PropertyIn("Id", 
      DetachedCriteria.For<MeasureDomain>() 
       .SetProjection(Projections.Property("MeasureSet.Id")) 
       .Add(Subqueries.PropertyIn("Id", 
        DetachedCriteria.For<MeasureSubDomain>() 
        .SetProjection(Projections.Property("MeasureDomain.Id")) 
        .Add(Subqueries.PropertyIn("Id", 
         DetachedCriteria.For<MeasureControl>() 
         .SetProjection(Projections.Property("MeasureSubDomain.Id")) 
         .Add(Subqueries.PropertyIn("Id", 
          DetachedCriteria.For<Measure>() 
          .SetProjection(Projections.Property("MeasureControl.Id")))))))))) 
          .SetCacheable(true) 
          .Future<MeasureSet>().ToList(); 

基類

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 

namespace GRCcontrol.Domain.Entities 
{ 
    /// <summary> 
    /// Base class for domain entities based on NHibernate. 
    /// </summary> 
    /// <typeparam name="TId">The type of the id.</typeparam> 
    public abstract class PersistentEntity<TId> : IEquatable<PersistentEntity<TId>> 
    { 
     /// <summary> 
     /// Gets or sets the id. 
     /// </summary> 
     /// <value> 
     /// The id. 
     /// </value> 
     public virtual TId Id { get; protected set; } 

     /// <summary> 
     /// Determines whether the specified <see cref="System.Object" /> is equal to this instance. 
     /// </summary> 
     /// <param name="obj">The <see cref="System.Object" /> to compare with this instance.</param> 
     /// <returns> 
     /// <c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>. 
     /// </returns> 
     public override bool Equals(object obj) 
     { 
      return Equals(obj as PersistentEntity<TId>); 
     } 
     /// <summary> 
     /// Determines whether the specified obj is transient. 
     /// </summary> 
     /// <param name="obj">The obj.</param> 
     /// <returns> 
     /// <c>true</c> if the specified obj is transient; otherwise, <c>false</c>. 
     /// </returns> 
     private static bool IsTransient(PersistentEntity<TId> obj) 
     { 
      return obj != null && 
       Equals(obj.Id, default(TId)); 
     } 
     /// <summary> 
     /// Gets the type of the unproxied type, since NHibernate's lazy loading technology, creates proxies from entities. 
     /// </summary> 
     /// <returns></returns> 
     private Type GetUnproxiedType() 
     { 
      return GetType(); 
     } 
     /// <summary> 
     /// Equalses the specified other. 
     /// </summary> 
     /// <param name="other">The other.</param> 
     /// <returns></returns> 
     public virtual bool Equals(PersistentEntity<TId> other) 
     { 
      if (other == null) 
       return false; 
      if (ReferenceEquals(this, other)) 
       return true; 
      if (!IsTransient(this) && 
       !IsTransient(other) && 
       Equals(Id, other.Id)) 
      { 
       var otherType = other.GetUnproxiedType(); 
       var thisType = GetUnproxiedType(); 

       return thisType.IsAssignableFrom(otherType) || 
        otherType.IsAssignableFrom(thisType); 
      } 

      return false; 
     } 
     /// <summary> 
     /// Returns a hash code for this instance. 
     /// </summary> 
     /// <returns> 
     /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. 
     /// </returns> 
     public override int GetHashCode() 
     { 
      if (Equals(Id, default(TId))) 
       return base.GetHashCode(); 

      return Id.GetHashCode(); 
     } 
    } 
    /// <summary> 
    /// Base class for domain entities based on NHibernate. 
    /// </summary> 
    public abstract class PersistentEntity : PersistentEntity<Guid> 
    { 
    } 
} 

我仍然得到所有屬性,所以還有我目前並不需要的審計等。 由於NHibernate不支持集合上的投影,我想知道我應該如何改變我的代碼以獲得更好的性能。

希望你能幫助我。

+0

你有什麼實際從該查詢想要的嗎?即。您是否需要MeasureSet.Code,MeasureSet.Description和MeasureSet.MeasureDomains?是否僅限於那些擁有子域的控件的測量集? – 2013-02-21 14:31:42

+0

@MartinErnst你的權利。我想要您在評論中說的內容,還需要MeasureDomain.Code,MeasureDomain.Description,MeasureDomain。MeasureSubDomains,然後是MeasureSubDomain.Code等。我不需要對審計,文件等的引用,所以我不想查詢它們。我的查詢也返回這些集合。 – 2013-02-21 14:35:03

回答

0

我花了幾個小時,在這個問題上的缺點,但我終於找到了解決辦法。該查詢也進行了優化,並需要四個調用數據庫:

IEnumerable<MeasureSet> measureSets = null; 

    var currentSession = LazySessionFactory.CurrentSession; 

    measureSets = currentSession.QueryOver<MeasureSet>().TransformUsing(Transformers.DistinctRootEntity) 
     .Fetch(m => m.MeasureDomains).Eager 
     .Future(); 

    var setIds = measureSets.Select(x => x.Id).ToArray(); 

    var domains = currentSession.QueryOver<MeasureDomain>().TransformUsing(Transformers.DistinctRootEntity) 
     .WhereRestrictionOn(x => x.MeasureSet.Id).IsIn(setIds).Fetch(m => m.MeasureSubDomains).Eager.Future(); 
    var domainIds = domains.Select(x => x.Id).ToArray(); 

    var subDomains = currentSession.QueryOver<MeasureSubDomain>().TransformUsing(Transformers.DistinctRootEntity) 
     .WhereRestrictionOn(x => x.MeasureDomain.Id).IsIn(domainIds).Fetch(m => m.MeasureControls).Eager.Future(); 
    var subDomainIds = subDomains.Select(x => x.Id).ToArray(); 

    var controls = currentSession.QueryOver<MeasureControl>().TransformUsing(Transformers.DistinctRootEntity) 
     .WhereRestrictionOn(x => x.MeasureSubDomain.Id).IsIn(subDomainIds).Fetch(m => m.Measures).Eager.Future(); 
    var controlIds = controls.Select(x => x.Id).ToArray(); 

    currentSession.QueryOver<Measure>().TransformUsing(Transformers.DistinctRootEntity) 
     .WhereRestrictionOn(x => x.MeasureControl.Id).IsIn(controlIds).Future(); 

    return measureSets.AsQueryable(); 

當你有一個更好的解決方案,然後這一個,請給我的答案迴應。

0

我想你真正想要的是預先抓取:

measureSets = LazySessionFactory.CurrentSession.CreateCriteria<MeasureSet>() 
    .SetFetchMode("MeasureDomains", FetchType.Eager) 
    .SetFetchMode("MeasureDomains.MeasureSubDomains", FetchType.Eager) 
    .SetFetchMode("MeasureDomains.MeasureSubDomains.MeasureControls", FetchType.Eager) 
    .SetCacheable(true) 
    .Future<MeasureSet>().ToList(); 

幾乎做你想要的不同之處在於它不會排除那些沒有域/子域/控制任何measuresets

如果這還不夠好,你可以通過添加限制它:

measureSets = LazySessionFactory.CurrentSession.CreateCriteria<MeasureSet>() 
    .Add(Subqueries.PropertyIn("Id", 
     DetachedCriteria.For<Measure>() 
      .CreateAlias("MeasureControl", "mc") 
      .CreateAlias("mc.MeasureSubDomain", "msd") 
      .CreateAlias("msd.MeasureDomain", "md") 
      .SetProjection(Projections.Property("md.MeasureSet.id"))) 
    .SetFetchMode("MeasureDomains", FetchType.Eager) 
    .SetFetchMode("MeasureDomains.MeasureSubDomains", FetchType.Eager) 
    .SetFetchMode("MeasureDomains.MeasureSubDomains.MeasureControls", FetchType.Eager) 
    .SetCacheable(true) 
    .Future<MeasureSet>().ToList(); 

(我對你們模型的其餘部分的一些假設) 氏但是小號確實有需要再選擇這可能會影響性能(因人而異)

+0

這個查詢在我的修改後仍然有效,但是根實體被多次添加。我想,讓我們添加DistinctRootEntity轉換器,但是會引發一個異常:Object與目標類型不匹配。 GRCcontrol.Domain.Entities.PersistentEntity'1 [[System.Guid,mscorlib,Version = 4.0.0.0,Culture = neutral,PublicKeyToken = b77a5c561934e089]]的getter發生異常。「} – 2013-02-22 07:47:47

+0

您是否實現了Equals(和GetHashCode)你的實體? – 2013-02-22 09:21:18

+0

我已經用基類實現更新了我的問題 – 2013-02-22 09:32:40