Свободный NHibernate: Как создать двунаправленное отображение один-ко-многим? - PullRequest
44 голосов
/ 22 ноября 2008

Основной вопрос : Как создать двунаправленную карту «один ко многим» в Fluent NHibernate?

Детали:

У меня есть родительский объект со многими детьми. В моем случае для ребенка бессмысленно не иметь родителя, поэтому в базе данных я бы хотел, чтобы внешний ключ к родителю имел ограничение NOT NULL. Я автоматически генерирую свою базу данных из сопоставления Fluent NHibernate.

У меня есть родитель со многими дочерними объектами, например:

public class Summary
{
   public int id {get; protected set;}

   public IList<Detail> Details {get; protected set;}
}

public  class Detail
{
   public int id {get; protected set;}

   public string ItemName {get; set;}

  /* public Summary Owner {get; protected set;} */ //I think this might be needed for bidirectional mapping?
}

Вот отображение, с которого я начал:

public class SummaryMap : ClassMap<Summary>
{
    public SummaryMap()
    {
        Id(x => x.ID);

        HasMany<Detail>(x => x.Details);
    }
}

public class DetailMap : ClassMap<Detail>
{
    public DetailMap()
    {
        Id(x => x.ID);

        Map(x => x.ItemName).CanNotBeNull();
    }
}

В таблице сведений, Summary_id должен быть не нулевым, потому что в моем В этом случае бессмысленно иметь объект Detail, не прикрепленный к итоговый объект. Однако простое использование карты HasMany () оставляет внешний ключ Summary_id обнуляемым.

В документах NHibernate (http://www.hibernate.org/hib_docs/nhibernate/html/collections.html)) я обнаружил, что «если требуется родитель, используйте двунаправленную связь« один ко многим ».

Так как мне создать двунаправленную карту «один ко многим» в Fluent NHibernate?

1 Ответ

55 голосов
/ 22 ноября 2008

Чтобы получить двунаправленную связь со столбцом ненулевого внешнего ключа в таблице Details, можно добавить предлагаемое свойство Owner, отображение References (...). CanNotBeNull () в классе DetailsMap и завершить Summary. обратный.

Чтобы избежать наличия двух разных столбцов внешнего ключа для двух направлений связи, вы можете либо указать имена столбцов вручную, либо присвоить имена свойств таким образом, чтобы дать одинаковое имя столбца для обоих направлений. В этом случае я предлагаю переименовать свойство Details.Owner в Details.Summary.

Я создал итоговый идентификатор, сгенерированный по инкременту, чтобы избежать проблем при вставке в таблицу, поскольку в Сводной информации нет столбцов, кроме идентификатора.

Домен:

public class Detail
{
    public int id { get; protected set; }
    public string ItemName { get; set; }

    // Renamed to use same column name as specified in the mapping of Summary.Details
    public Summary Summary {get; set;} 
}

public class Summary
{
    public Summary()
    {
        Details = new List<Detail>();
    }

    public int id { get; protected set; }
    public IList<Detail> Details { get; protected set; }
}

Отображение:

public class DetailMap : ClassMap<Detail>
{
    public DetailMap()
    {
        Id(x => x.id)
            .GeneratedBy.Native();

        Map(x => x.ItemName)
            .CanNotBeNull();

        References<Summary>(x => x.Summary)
            // If you don't want to rename the property in Summary,
            // you can do this instead:
            // .TheColumnNameIs("Summary_id")
            .CanNotBeNull();
    }
}

public class SummaryMap : ClassMap<Summary>
{
    public SummaryMap()
    {
        Id(x => x.id)
            .GeneratedBy.Increment();

        HasMany<Detail>(x => x.Details)
            .IsInverse()
            .AsBag(); // Use bag instead of list to avoid index updating issues
    }
}
...