Свободный NHibernate - Как сопоставить столбец внешнего ключа как свойство

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

public class Company {
    public Guid ID { get; set; }
    public Sector Sector { get; set; }
    public Guid SectorID { get; set; }
}

public class Sector {
    public Guid ID { get; set; }
    public string Name { get; set; }
}

В порядке. Я хочу, чтобы SectorID объекта Company был заполнен после того, как я перейду:

(new Company()).Sector = new Sector() { Name="asdf" }

и сделайте промывку.

Используемое мною отображение создает дополнительный столбец в базе данных с именем Sector_Id в таблице Company, но он недоступен в качестве свойства в Company. Я хочу, чтобы свойство SectorID было заполнено.

Отображение, которое я сейчас использую в CompanyMap:

References(c => c.Sector).Cascade.All();

У кого-нибудь есть идеи?


Спасибо за ваш ответ. К сожалению, если я выберу второй вариант (установите имя столбца столбца таким же, как свойство, или установите Map(x => x.SectorID, "Sector_Id"), я получу сообщение об ошибке:

System.IndexOutOfRangeException: недопустимый индекс 7 для этой коллекции SqlParameterCollection с Count = 7.

Возможно, мне придется сделать первый вариант, но я обеспокоен тем, что при вызове SectorID get будет запущен дополнительный запрос, поскольку он извлекает сам сектор из базы данных (если только он не загружен с нетерпением, что немного затруднительно).

Я удивлен, что на этот вопрос нет простого ответа.


ВАУ! Если я использую

public virtual Guid SectorID
{
    get { return Sector.ID;
}   

тогда nhibernate достаточно умен, чтобы знать, что столбец Sector_id в запросе Organization на самом деле то же самое, что и Sector.ID, и он возвращает его под капотами. Он не отправляет дополнительный запрос, даже если вы выполняете ленивую загрузку. Я впечатлен!


В качестве продолжения ... Похоже, что спящий режим на самом деле не написан, чтобы иметь возможность отображать столбец внешнего ключа в объектах. Хотя это может быть немного неудобно для веб-интерфейсов, это имеет смысл, поскольку на самом деле это проблема постоянства, а не проблема объекта. Я использую asp.net MVC и написал настраиваемый связыватель модели, который будет принимать поле ввода имени контакта (а не ContactID), создать новый контакт с идентификатором того, что находится в тексбоксе, а затем применить его к свойство Модели. Это позволяет обойти проблему с раскрывающимися списками в веб-интерфейсах. Выложу код, если кому интересно.


person Community    schedule 01.04.2009    source источник


Ответы (3)


Это легко сделать с помощью свойства формулы.

public class Company {
  public virtual Guid Id { get; set; }
  public virtual Guid? SectorId { get; set; }
  public virtual Sector Sector { get; set; }
}

public class CompanyMap : ClassMap<Company> {
  public CompanyMap() {
    Id(x => x.Id); // Maps to a column named "Id"
    References(x => x.Sector); // Maps to a column named "Sector_id", unless you change the NHibernate default mapping rules.
    Map(x => x.SectorId).Formula("[Sector_id]");
  }    
}

Это должно действовать именно так, как вы хотите. Когда Company новый, SectorId будет нулевым; когда Company извлекается из БД, SectorId будет заполнено заданным значением формулы. SectorId отображается как свойство, что делает его действительно удобным для работы с раскрывающимися списками веб-страниц и т. Д. При сохранении вам все равно потребуется привязать «настоящую» ассоциацию. Предполагая, что SectorId был выбран в форме ...

using (var txn = session.BeginTransaction()) {
  // Set the FK reference.
  company.Sector = session.Load<Sector>(company.SectorId);
  // Save the new record.
  session.Save(company);
  // Commit the transaction.
  txn.Commit();
}
person Jarrett Meyer    schedule 06.12.2010
comment
Я даю вам очки за решение полученной мной ошибки, но это кажется совершенно не интуитивно понятным. Это похоже на проблему дизайна в NHibernate, если он не может справиться с таким распространенным сценарием, как наличие как FK ID, так и связанного экземпляра объекта в качестве свойств. - person Lance Hunt; 22.02.2011

Стив, тебе не нужно свойство ForeignKey в классе POCO.

Например, если вы попытаетесь получить идентификатор автора статьи, выбор присоединения не будет выполнен.

var authorID = Article.Author.ID

person Alexey Zakharov    schedule 08.06.2010

Две мысли: во-первых, разве что-то подобное не достигнет того, чего вы хотите?

public class Company {
    public Guid ID { get; set; }
    public Sector Sector { get; set; }
    public Guid SectorID {
        get { return Section.ID; }
        // Really not sure what behavior your setter should have here; Maybe it shouldn't even have one?
        set { Sector = new Sector { ID = value }; }
    }
}

Во-вторых, когда вы говорите, что отображение создало столбец в базе данных с именем Sector_Id, является ли он добавлением к созданному вами столбцу с именем SectorID? В таком случае вы можете изменить имя столбца так, чтобы оно использовало правильное имя (вот документация по сопоставлениям, см. несколько заголовков ниже «Определение имени столбца»).

Кроме того, сопоставляете ли вы свойство SectorID (например, «Map (x => x.SectorID,« Sector_Id »)»)?

person Chris Shaffer    schedule 02.04.2009