беглый nhibernate HasOne WithForeignKey не работает - PullRequest
23 голосов
/ 13 марта 2009

Всякий раз, когда я загружаю класс Task, свойство Document всегда равно null, несмотря на наличие данных в БД.

Класс задачи:

public class Task
{
    public virtual Document Document { get; set; }

Переопределение сопоставления задач для AutoPersistenceModel:

public void Override(AutoMap<Task> mapping)
{
    mapping.HasOne(x => x.Document)
        .WithForeignKey("Task_Id");

Как видно из того, что NHProf говорит, что выполняется, условие соединения неверно, WithForeignKey, похоже, не вступает в силу. На самом деле, я могу написать любую строку в приведенном выше коде, и это не имеет значения.

FROM   [Task] this_
    left outer join [Document] document2_
    on this_.Id = document2_.Id

Должно быть:

FROM   [Task] this_
    left outer join [Document] document2_
    on this_.Id = document2_.Task_Id

Если я взламываю данные в БД, чтобы идентификаторы совпадали, тогда данные загружаются, но, очевидно, это неверно - но, по крайней мере, доказывает, что загружает данные.

Редактировать: копаясь в беглом источнике nhib, чтобы найти XML, получается это:

<one-to-one foreign-key="Task_Id" cascade="all" name="Document" class="MyProject.Document, MyProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> 

Редактировать: вот схема:

CREATE TABLE [dbo].[Document](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Task_Id] [int] NOT NULL,

CREATE TABLE [dbo].[Task](
[Id] [int] IDENTITY(1,1) NOT NULL,

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

Спасибо

Andrew

Ответы [ 6 ]

93 голосов
/ 05 марта 2010

Я столкнулся с той же проблемой сегодня. Я считаю, что хитрость заключается не в том, чтобы использовать .ForeignKey (...) с отображением .HasOne, а вместо этого использовать .PropertyRef (...). Ниже описано, как определить отношение «один к одному» между организацией (родительской) и ее администратором (дочерней):

HasOne(x => x.Admin).PropertyRef(r => r.Organisation).Cascade.All();

Администратор имеет простую ссылку на Организацию, используя свой внешний ключ:

References(x => x.Organisation, "ORAD_FK_ORGANISATION").Not.Nullable();

При извлечении Организации это приведет к загрузке правильной записи администратора и правильному каскадному обновлению и удалению.

6 голосов
/ 13 марта 2009

Вы должны использовать:

Ссылки (x => x.Document, "DocumentIdColumnOnTask")

5 голосов
/ 13 марта 2009

Я думаю, что проблема здесь в том, что соглашение «HasOne» означает, что вы указываете на другую вещь (стандартный реляционный способ сказать «многие к одному» / «один к одному»); Помещая Task_ID в документ, фактическая связь - это HasMany, но у вас есть какое-то неявное понимание того, что в одной задаче будет только один документ.

Извините - я не знаю, как это исправить, но мне будет интересно узнать, каково это решение (я не использую NHibernate или Fluent NHibernate, но я изучал его для использования в будущем). Решение (от кого-то с очень малой идеей) состоит в том, чтобы сделать Documents коллекцией в Task, а затем предоставить свойство Document, которое возвращает первое в коллекции (используя интерфейс, который скрывает свойство Documents, чтобы никто не думал, что они могут добавить новинки к нему).

Просматривая документацию и обдумывая ответ eulerfx, возможно, такой подход будет примерно таким:

References(x => x.Document)
    .TheColumnNameIs("ID")
    .PropertyRef(d => d.Task_ID);

РЕДАКТИРОВАТЬ: Именно поэтому этот ответ имеет соответствующее решение: правильный путь заключается в обновлении схемы базы данных, чтобы соответствовать цели кода. Это означает добавление DocumentID к таблице задач, поэтому существует связь «многие к одному» между задачей и документом. Если изменения схемы были невозможны, References () будет подходящим разрешением.

2 голосов
/ 27 марта 2012

Я пробовал это решение:

только в документе:

mapping.HasOne(x => x.Task).ForeignKey("Task_ID").Constrained().Cascade.All();
0 голосов
/ 30 декабря 2011

Я боролся с той же проблемой Has One и, наконец, обнаружил, что это сработало:

public class ParentMap : ClassMap<Parent>
{
    public ParentMap()
    {
        Id(x => x.Id);
        HasOne(s => s.Child).Cascade.All();
    }
}

 public class ChildMap : ClassMap<Model.Child>
{
    public ChildMap()
    {
        Id(x => x.Id);
        HasOne(s => s.Parent).Constrained().ForeignKey();           
    }
}
0 голосов
/ 13 марта 2009

Как указал eulerfx,

структура таблицы указывает, что может быть несколько документов для задачи

и Крис заявил:

Помещая Task_ID в документ, фактическим отношением является HasMany, но у вас есть какое-то неявное понимание того, что для каждой задачи будет только один документ.

Это, конечно, правильно, поэтому я изменил его, чтобы у Task был обнуляемый Document_Id.

Спасибо вам обоим за помощь!

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

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