2012-08-14 86 views
2

我有一個複雜的情況,我需要用NHibernate映射三個不同的類。 Class1(Branch.cs)具有Class2(Employee.cs)對象的集合。同時Class2也有一個Class3(Contacts.cs)對象的集合。
由於數據非常龐大,我使用fetch關鍵字在單個查詢中檢索數據。
我使用的查詢爲

查詢1 - 「從支路B內連接抓取b.EmployeeË內連接抓取e.Contacts」 - 單查詢,但重複的結果。
查詢2 - 「來自分支b內部聯合提取b.Employee」 - 多個查詢,所需結果。

我在映射文件中使用了包。查詢結果似乎有重複的結果。 如何刪除重複結果以及在單個查詢中檢索數據。 我包括映射文件以及類。NHibernate集合獲取,重複數據

Contacts.hbm.xml

<?xml version="1.0" encoding="utf-8"?> 
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHibernateSample" namespace="NHibernateSample"> 
    <class name="Contacts" table="Contacts"> 
     <id name="EmployeeID"/> 
     <property name="EmployeeID"/> 
     <property name="Mobile"/> 
     <property name="Alternate"/> 
    </class> 
</hibernate-mapping> 

Branch.hbm.xml

<?xml version="1.0" encoding="utf-8"?> 
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHibernateSample" namespace="NHibernateSample"> 
    <class name="Branch" table="Branch"> 
     <id name="BranchCode"/> 
     <property name="BranchCode"/> 
     <property name="BranchName"/> 
     <bag name="EmployeeList" cascade="all-delete-orphan" inverse="false" batch-size="10000"> 
      <key column="BranchCode"/> 
      <one-to-many class="Employee" /> 
     </bag> 
    </class> 

</hibernate-mapping> 

Employee.hbm.xml

<?xml version="1.0" encoding="utf-8"?> 
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHibernateSample" namespace="NHibernateSample"> 
    <class name="Employee" table="Employee"> 
     <id name="EmployeeId"/> 
     <property name="EmployeeId"/> 
     <property name="FirstName"/> 
     <property name="LastName"/> 
     <property name="BranchCode"/> 
     <bag name="Contact" cascade="all-delete-orphan" inverse="false" batch-size="10000"> 
      <key column="EmployeeID"/> 
      <one-to-many class="Contacts" /> 
     </bag> 
    </class> 
</hibernate-mapping> 

Contacts.cs

using System; 
using System.Collections.Generic; 
using System.Text; 

namespace NHibernateSample 
{ 
    public class Contacts 
    { 
     String employeeID; 
     String mobile; 
     String alternate; 

     public Contacts() 
     { } 


     public virtual String EmployeeID 
     { 
      get { return employeeID; } 
      set { employeeID = value; } 
     } 

     public virtual String Mobile 
     { 
      get { return mobile; } 
      set { mobile = value; } 
     }   
     public virtual String Alternate 
     { 
      get { return alternate; } 
      set { alternate = value; } 
     } 
    } 
} 

Employee.cs

using System; 
using System.Collections.Generic; 
using System.Text; 

namespace NHibernateSample 
{ 
    public class Employee 
    { 
     String employeeId; 
     String firstName; 
     String lastName; 
     String branchCode; 
     List<Contacts> contact = new List<Contacts>(); 

     public virtual List<Contacts> Contact 
     { 
      get { return contact; } 
      set { contact = value; } 
     } 
     public virtual String EmployeeId 
     { 
      get { return employeeId; } 
      set { employeeId = value; } 
     } 

     public virtual String FirstName 
     { 
      get { return firstName; } 
      set { firstName = value; } 
     } 

     public virtual String LastName 
     { 
      get { return lastName; } 
      set { lastName = value; } 
     } 

     public virtual String BranchCode 
     { 
      get { return branchCode; } 
      set { branchCode = value; } 
     } 

     public Employee() 
     { } 
    } 
} 

Branch.cs

using System.Collections.Generic; 
using System.Text; 
using System; 


namespace NHibernateSample 
{ 
    [Serializable] 
    public class Branch 
    { 
     private String branchCode; 
     private String branchName; 
     private IList<Employee> employeeList = new List<Employee>(); 

     public virtual IList<Employee> EmployeeList 
     { 
      get { return employeeList; } 
      set { employeeList = value; } 
     } 
     public virtual String BranchCode 
     { 
      get { return branchCode; } 
      set { branchCode = value; } 
     } 

     public virtual String BranchName 
     { 
      get { return branchName; } 
      set { branchName = value; } 
     } 

     public Branch() { } 
    } 
} 

回答

5

這是NHibernate的一個問題,他們將無法修復。

你可以得到的結果在通過應用DistinctEntityTransformer第一級是正確的,這是一個建在NHibernate的變壓器和u應使用

QueryOver.TranformUsing(Tranformers.DistinctEntityTransformer). 

多級其應用到queryover對象,如您您需要編寫自己的變壓器並使用它來代替不同的實體變壓器。你可以使用NHibernate提供的不同的實體變換器類似的邏輯來修復複製的細節。

編輯:這是一個這樣的實現:

public class MultiLevelDistinctEntityTransformer : IResultTransformer 
{ 
    private readonly Dictionary<Type, List<String>> _fetchedCollectionProperties; // used to know which properties are fetched so you don't fetch more details than required 

    public MultiLevelDistinctEntityTransformer(Dictionary<Type, List<String>> fetchedCollectionProperties) 
    { 
     _fetchedCollectionProperties = fetchedCollectionProperties; 
    } 

    public object TransformTuple(object[] tuple, string[] aliases) 
    { 
     return tuple.Last(); 
    } 

    public IList TransformList(IList list) 
    { 
     if (list.Count == 0) 
      return list; 
     var result = (IList) Activator.CreateInstance(list.GetType()); 
     var distinctSet = new HashSet<Entity>(); 
     foreach (object item in list) 
     { 
      var entity = item as Entity; // Entity is the base class of my nhibernate classes 
      if (entity == null) 
       continue; 
      if (distinctSet.Add(entity)) 
      { 
       result.Add(item); 
       HandleItemDetails(item); 
      } 
     } 
     return result; 
    } 

    private void HandleItemDetails(object item) 
    { 
     IEnumerable<PropertyInfo> collectionProperties = 
      item.GetType().GetProperties().Where(
       prop => 
       prop.IsCollectionProperty()/*extension method which checks if the object inherits from ICollection*/ && 
       _fetchedCollectionProperties.ContainsKey(item.GetType()) &&// get only the fetched details 

       _fetchedCollectionProperties[item.GetType()].Contains(prop.Name)); 
     foreach (PropertyInfo collectionProperty in collectionProperties) 
     { 
      dynamic detailList = collectionProperty.GetValue(item, null); 
      if (detailList != null) 
      { 
       dynamic uniqueValues = 
        Activator.CreateInstance(
         typeof (List<>).MakeGenericType(collectionProperty.PropertyType.GetGenericArguments()[0])); 
       var distinct = new HashSet<Entity>(); 
       foreach (var subItem in detailList) 
       { 
        var entity = subItem as Entity; 
        if (distinct.Add(entity)) 
        { 
         uniqueValues.Add(subItem); 
         HandleItemDetails(subItem); 
        } 
       } 
       collectionProperty.SetValue(item, uniqueValues, null); 
      } 
     } 
    } 
} 
+0

感謝您的答覆。 – 2012-08-14 11:15:04

+0

它解決了你的問題@ChaturvediDewashish? – 2012-08-14 11:20:55

+0

我會在我的應用程序中實現它。目前我正在尋找其他一些替代方法,如內部收集的批量大小。通過將lazy = false和批量大小設置爲幾千,它會起作用嗎? – 2012-08-14 12:45:37