2

私は複雑な状況にあり、NHibernateで3つの異なるクラスをマッピングする必要があります。Class1(Branch.cs)には、Class2(Employee.cs)オブジェクトのコレクションがあります。同時に、Class2にはClass3(Contacts.cs)オブジェクトのコレクションもあります。
データは非常に大きいため、fetchキーワードを使用して単一のクエリでデータを取得しました。
クエリを

Query1として使用しました-「ブランチb内部結合フェッチb.Employeee内部結合フェッチe.Contactsから」 -単一のクエリですが、結果が重複しています。
Query2-「ブランチb内部結合フェッチb.Employeeから」 -複数のクエリ、必要な結果。

マッピングファイルでバッグを使用しました。クエリ結果の結果が重複しているようです。重複する結果を削除する方法と、単一のクエリでデータを取得する方法。クラスだけでなくマッピングファイルも含めています。

連絡先.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() { }
    }
}
4

1 に答える 1

5

これはNHibernateの問題であり、修正されません。

DistinctEntityTransformerを適用することで、最初のレベルで正しい結果を得ることができます。これはNHibernateに組み込まれているトランスフォーマーであり、uを使用してqueryoverオブジェクトに適用する必要があります。

QueryOver.TranformUsing(Tranformers.DistinctEntityTransformer).

問題などのマルチレベルでは、独自のトランスフォーマーを作成し、個別のエンティティトランスフォーマーの代わりにそれを使用する必要があります。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);
            }
        }
    }
}
于 2012-08-14T10:45:10.270 に答える