Свободный NHibernate - Как сопоставить столбец внешнего ключа как свойство - PullRequest
9 голосов
/ 02 апреля 2009

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

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; }
}

Ok. То, что я хочу, это 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 для этой коллекции SqlParameterCollect со счетчиком = 7.

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

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


WOW! Если я использую

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

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


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

Ответы [ 3 ]

13 голосов
/ 06 декабря 2010

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

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();
}
2 голосов
/ 08 июня 2010

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

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

var authorID = Article.Author.ID

2 голосов
/ 02 апреля 2009

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

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 ")")?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...