Миграция Nhibernate от 1.0.2.0 до 2.1.2 и проблемы сохранения много-к-одному - PullRequest
0 голосов
/ 18 мая 2010

у нас есть старое, большое приложение asp.net с nhibernate, которое мы расширяем и модернизируем некоторые его части. Использованный NHibernate был довольно стар (1.0.2.0), поэтому мы решили обновить его до (2.1.2) для новых функций. Файлы HBM генерируются через пользовательский шаблон с MyGeneration. Все прошло довольно гладко, кроме одного.

Допустим, у нас есть объекты Blog и Post. В блоге может быть много постов, поэтому пост будет иметь отношения один-на-один. Благодаря тому, как работает это приложение, связь осуществляется не через первичные ключи, а через столбец Blog.Reference.

Примеры карт и .cs файлов:

<?xml version="1.0" encoding="utf-8" ?>

    <id name="Id" column="Id" type="Guid">
        <generator class="assigned"/>
    </id>
    <property column="Reference" type="Int32" name="Reference" not-null="true" />
    <property column="Name" type="String" name="Name" length="250" />
</class>

<?xml version="1.0" encoding="utf-8" ?>

    <id name="Id" column="Id" type="Guid">
        <generator class="assigned"/>
    </id>

    <property column="Reference" type="Int32" name="Reference" not-null="true" />
    <property column="Name" type="String" name="Name" length="250" />
    <many-to-one name="Blog" column="BlogId" class="SampleNamespace.BlogEntity,SampleNamespace" property-ref="Reference" />
</class>

И файлы классов

class BlogEntity
{
    public Guid Id { get; set; }
    public int Reference { get; set; }
    public string Name { get; set; }
}

class PostEntity
{
    public Guid Id { get; set; }
    public int Reference { get; set; }
    public string Name { get; set; }
    public BlogEntity Blog { get; set; }
}

Теперь допустим, что у меня есть блог с идентификатором 1D270C7B-090D-47E2-8CC5-A3D145838D9C и со ссылкой 1

В старом nhibernate такое было возможно:

        //this Blog already exists in database
        BlogEntity blog = new BlogEntity();
        blog.Id = Guid.Empty;
        blog.Reference = 1; //Reference is unique, so we can distinguish Blog by this field
        blog.Name = "My blog";

        //this is new Post, that we are trying to insert
        PostEntity post = new PostEntity();
        post.Id = Guid.NewGuid();
        post.Name = "New post";
        post.Reference = 1234;
        post.Blog = blog; 

        session.Save(post);

Однако в новой версии я получаю исключение, которое не может вставить NULL в Post.BlogId. Как я понимаю, в старой версии для nhibernate было достаточно иметь поле Blog.Reference, и оно могло бы извлекать сущность по этому полю и прикреплять его к PostEntity, и при сохранении PostEntity все будет работать правильно. И, как я понимаю, новый NHibernate пытается получить только по Blog.Id.

Как это решить? Я не могу изменить дизайн БД и не могу назначить Id для BlogEntity, так как объекты находятся вне моего контроля (они предварительно заполнены как общие «объекты», подобные этому из внешнего источника)

Ответы [ 3 ]

0 голосов
/ 19 мая 2010

это

blog.Id = Guid.Empty

переводится как ноль в БД. Поэтому, когда вы изменяете его (как следует из примера кода), вы явно устанавливаете нулевое значение в идентификаторе BlogEntity.

Это ошибка, которую вы получаете, и она не имеет отношения к столбцу / свойству «Ссылка».

Что касается вопроса о том, что вы можете сделать ... ну, вам не нужно присоединять ORM к Guids! Вы можете сделать соединения в столбце Ссылка ...

0 голосов
/ 10 июня 2010

Отвечая на мой собственный вопрос.

Проблема заключалась в том, что nhibernate выполнял вызов DB для получения BlogEntity с идентификатором 00000000-0000-0000-0000-000000000000. Конечно, в БД ничего не попало, поэтому попытался вставить ноль

И в логах было ясно видно, почему это происходило

Невозможно определить, является ли BlogEntity с присвоенный идентификатор 00000000-0000-0000-0000-000000000000 преходящий или отстраненный; Запросы база данных. Используйте явный Save () или Update () в сеансе, чтобы предотвратить это.

Решил это моя реализация IInterceptor, передав его в Session и особенно его метод bool? IsTransient(object entity)

И проблема решена.

0 голосов
/ 18 мая 2010

Мне кажется очень странным, что код работал в NH 1. Но, поскольку он все равно не работает в данный момент, я думаю, что сначала нужно искать сущность блога в запросе:

var criteria = DetachedCriteria.For<Blog>();
criteria.Add(Expression.Eq("Reference", 1));
var blog = criteria.GetExecutableCriteria(session).List<Blog>().FirstOrDefault();

post.Blog = blog;
session.Save(post);
...