Свободный nhibernate HasOne WithForeignKey не работает
Всякий раз, когда я загружаю класс Task, свойство Document всегда равно null, несмотря на наличие данных в db.
Класс задачи:
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
Если я взломаю данные в db, чтобы идентификаторы совпадали, тогда данные загружаются, но, очевидно, это неверно - но, по крайней мере, он доказывает, что он загружает данные.
Изменить: рыться в свободном источнике 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" />
Изменить: heres the schema:
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,
У кого-нибудь есть идеи?
Спасибо
Эндрю
Ответы
Ответ 1
Я думаю, что проблема здесь в том, что соглашение "HasOne" означает, что вы указываете на другое (стандартный реляционный способ сказать "много в один" / "один к одному" ); Поместив Task_ID в документ, фактическое отношение является HasMany, но у вас есть какое-то неявное понимание того, что на одну задачу будет только один документ.
Извините - я не знаю, как это исправить, но мне будет интересно узнать, что такое решение (я не использую NHibernate или Fluent NHibernate, но я изучал его для использования в будущем). Решение (от кого-то с очень маленькой идеей) заключалось бы в том, чтобы сделать документы коллекцией в Task, а затем предоставить свойство Document, которое возвращает первый в коллекции (используя интерфейс, который скрывает свойство Documents, поэтому никто не может подумать, что он может добавить новые предметы к нему).
Просматривая документацию и рассматривая ответ eulerfx, возможно, подход будет примерно таким:
References(x => x.Document)
.TheColumnNameIs("ID")
.PropertyRef(d => d.Task_ID);
РЕДАКТИРОВАТЬ: Только так у этого ответа есть соответствующее решение: правильный путь - обновить схему базы данных в соответствии с намерением кода. Это означает добавление DocumentID в таблицу Task, так что между Task и Document существует взаимосвязь Many-To-One. Если изменения схемы не были возможны, ссылка() была бы соответствующим разрешением.
Ответ 2
Сегодня я столкнулся с тем же вопросом. Я считаю, что трюк не использовать .ForeignKey(...) с отображением .HasOne, но вместо этого использовать .PropertyRef(...). Ниже описано, как я определяю отношения "один-к-одному" между организацией (родителем) и ее администратором (дочерним):
HasOne(x => x.Admin).PropertyRef(r => r.Organisation).Cascade.All();
Администратор имеет простую ссылку на организацию, используя свой внешний ключ:
References(x => x.Organisation, "ORAD_FK_ORGANISATION").Not.Nullable();
При получении Организации это загрузит правильную запись администратора и правильно каскадирует обновления и удаляет.
Ответ 3
Вы должны использовать:
Ссылки (x = > x.Document, "DocumentIdColumnOnTask" )
Ответ 4
Я пробовал это решение:
только в документе:
mapping.HasOne(x => x.Task).ForeignKey("Task_ID").Constrained().Cascade.All();
Ответ 5
Как указывал eulerfx,
структура таблицы указывает, что, возможно, могут быть запущены документы для задачи
и Крис заявил:
Поместив Task_ID в документ, фактическое отношение является HasMany, но у вас есть какое-то неявное понимание того, что на одну задачу будет только один документ.
Это, конечно, правильно, поэтому я отменил его, так что задача имеет нулевую Document_Id.
Спасибо вам обоим за помощь!
Я щелкнул монеткой для принятого ответа, если бы я мог пометить оба, я бы!
Ответ 6
Я боролся с той же проблемой One 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();
}
}