Свободный NHibernate: отображение комплекса многие-ко-многим (с дополнительными столбцами) и настройка извлечения - PullRequest
5 голосов
/ 20 апреля 2010

Мне нужно сопоставление Fluent NHibernate, которое выполнит следующее (если ничего другого, я также возьму соответствующее сопоставление NHibernate XML и проведу обратный инжиниринг).


информация

У меня есть отношение многие ко многим между двумя сущностями: Parent и Child. Это достигается с помощью дополнительной таблицы для хранения идентификационных данных Родителя и Ребенка. Однако мне также нужно определить два дополнительных столбца в этом отображении, которые предоставляют больше информации об отношениях.

Примерно так я определил свои типы, по крайней мере соответствующие части (где Entity - это некоторый базовый тип, который предоставляет свойство Id и проверяет эквивалентность на основе этого идентификатора):

public class Parent : Entity
{
    public virtual IList<ParentChildRelationship> Children { get; protected set; }

    public virtual void AddChildRelationship(Child child, int customerId)
    {
       var relationship = new ParentChildRelationship
                        {
                           CustomerId = customerId,
                           Parent = this,
                           Child = child
                        };
       if (Children == null) Children = new List<ParentChildRelationship>();
       if (Children.Contains(relationship)) return;
       relationship.Sequence = Children.Count;
       Children.Add(relationship);
    }
}

public class Child : Entity
{
    // child doesn't care about its relationships
}

public class ParentChildRelationship
{
    public int CustomerId { get; set; }
    public Parent Parent { get; set; }
    public Child Child { get; set; }
    public int Sequence { get; set; }

    public override bool Equals(object obj)
    {
       if (ReferenceEquals(null, obj)) return false;
       if (ReferenceEquals(this, obj)) return true;
       var other = obj as ParentChildRelationship;
       if (return other == null) return false;

       return (CustomerId == other.CustomerId
           && Parent == other.Parent
           && Child == other.Child);
    }

    public override int GetHashCode()
    {
       unchecked
       {
           int result = CustomerId;
           result = Parent == null ? 0 : (result*397) ^ Parent.GetHashCode();
           result = Child == null ? 0 : (result*397) ^ Child.GetHashCode();
           return result;
       }
    }
}

Таблицы в базе данных выглядят примерно так (предполагается, что первичные / внешние ключи и простите синтаксис):

create table Parent (
   id int identity(1,1) not null
)

create table Child (
   id int identity(1,1) not null
)

create table ParentChildRelationship (
   customerId int not null,
   parent_id int not null,
   child_id int not null,
   sequence int not null
)

У меня все в порядке с Parent.Children, который является ленивым загруженным свойством. Тем не менее, ParentChildRelationship должен стремиться загрузить ParentChildRelationship.Child. Кроме того, я хочу использовать Join, когда я жду загрузки.

SQL при обращении к Parent.Children, NHibernate должен сгенерировать эквивалентный запрос к:

SELECT * FROM ParentChildRelationship rel LEFT OUTER JOIN Child ch ON rel.child_id = ch.id WHERE parent_id = ?

ОК, для этого у меня есть отображения, которые выглядят так:

ParentMap : ClassMap<Parent>
{
   public ParentMap()
   {
      Table("Parent");
      Id(c => c.Id).GeneratedBy.Identity();
      HasMany(c => c.Children).KeyColumn("parent_id");
    }
}

ChildMap : ClassMap<Child>
{
   public ChildMap()
   {
      Table("Child");
      Id(c => c.Id).GeneratedBy.Identity();
   }
}


ParentChildRelationshipMap : ClassMap<ParentChildRelationship>
{
   public ParentChildRelationshipMap()
   {
      Table("ParentChildRelationship");
      CompositeId()
                .KeyProperty(c => c.CustomerId, "customerId")
                .KeyReference(c => c.Parent, "parent_id")
                .KeyReference(c => c.Child, "child_id");
      Map(c => c.Sequence).Not.Nullable();
    }
}

Итак, в моем тесте, если я попытаюсь получить myParentRepo.Get(1).Children, он действительно получит мне все отношения и, когда я получаю доступ к ним из отношений, к дочерним объектам (например, я могу захватить их все, выполнив parent.Children.Select(r => r.Child).ToList()).

Однако SQL, который генерирует NHibernate, неэффективен. Когда я обращаюсь к parent.Children, NHIbernate делает SELECT * FROM ParentChildRelationship WHERE parent_id = 1, а затем SELECT * FROM Child WHERE id = ? для каждого ребенка в каждом отношении. Я понимаю, почему NHibernate делает это, но я не могу понять, как настроить сопоставление, чтобы сделать запрос NHibernate так, как я упоминал выше.

1 Ответ

2 голосов
/ 04 июня 2010

Я не понимаю, почему это не работает так, как вы это делаете, но я могу сказать вам, как бы это отобразить:

<class name="Parent">

    <id .../>

    <list name="Children" table="ParentChildRelationship">
        <key column="parent_id"/>
        <index column="Sequence"/>

        <composite-element>
            <property name="CustomerId"/>
            <many-to-one name="Child"/>
        </composite-element>
    </list>

</class>

<class name="Child">
    <id .../>
    <property .../>
</class>

Чтобы повысить производительность, попытайтесь заставить его извлекать множество-к-одному с помощью объединения:

      <many-to-one name="Child" fetch="join" />
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...