Nhibernate 从 1.0.2.0 迁移到 2.1.2 以及多对一保存问题

发布于 2024-09-02 03:57:21 字数 2481 浏览 10 评论 0原文

我们有一个旧的、大型的带有 nhibernate 的 ASP.NET 应用程序,我们正在扩展和升级它的某些部分。使用的 NHibernate 相当旧(1.0.2.0),因此我们决定升级到(2.1.2)以获得新功能。 HBM 文件是通过 MyGeneration 的自定义模板生成的。一切都很顺利,除了一件事。

假设我们必须反对博客和帖子。博客可以有很多帖子,因此帖子将具有多对一的关系。由于此应用程序的运行方式,关系不是通过主键完成的,而是通过 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; }
}

现在可以说我有一个 ID 为 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,因为对象超出了我的控制范围(它们是从外部源预填充为通用“对象”的)

we have an old, big asp.net application with nhibernate, which we are extending and upgrading some parts of it. NHibernate that was used was pretty old ( 1.0.2.0), so we decided to upgrade to ( 2.1.2) for the new features. HBM files are generated through custom template with MyGeneration. Everything went quite smoothly, except for one thing.

Lets say we have to objects Blog and Post. Blog can have many posts, so Post will have many-to-one relationship. Due to the way that this application operates, relationship is done not through primary keys, but through Blog.Reference column.

Sample mapings and .cs files:

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

And class files

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

Now lets say that i have a Blog with Id 1D270C7B-090D-47E2-8CC5-A3D145838D9C and with Reference 1

In old nhibernate such thing was possible:

        //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);

However, in new version, i get an exception that cannot insert NULL into Post.BlogId. As i understand, in old version, for nhibernate it was enough to have Blog.Reference field, and it could retrieve entity by that field, and attach it to PostEntity, and when saving PostEntity, everything would work correctly. And as i understand, new NHibernate tries only to retrieve by Blog.Id.

How to solve this? I cannot change DB design, nor can i assign an Id to BlogEntity, as objects are out of my control (they come prefilled as generic "ojbects" like this from external source)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

债姬 2024-09-09 03:57:21

对我来说,代码在 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);

It seems very strange to me that the code worked in NH 1. But, since it is not working at the moment anyway, I think you have to look for the blog entity in a query first:

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);
泪之魂 2024-09-09 03:57:21

blog.Id = Guid.Empty

在数据库中被翻译为空。因此,当您更改它时(如示例代码所示),您将显式地在 BlogEntity Id 上设置空值。

这是您收到的错误,与“参考”列/属性无关。

至于你能做什么的问题......好吧,你不必让 ORM 连接到 Guid!您可以在参考列上进行连接...

this

blog.Id = Guid.Empty

is translated as a null in the DB. So when you change it (as the sample code implies) you are explicitly setting a null value on the BlogEntity Id.

This is the error you are receiving and is irrelevant of the "Reference" column/property.

As for the question of what you can do... well you don't have to make the ORM joins on the Guids! You can make the joins on the Reference column...

她说她爱他 2024-09-09 03:57:21

回答我自己的问题。

问题是 nhibernate 正在访问数据库来检索 ID 为 00000000-0000-0000-0000-000000000000 的 BlogEntity。当然,在数据库中它什么也没有得到,所以它尝试插入 null

并且在日志中清楚地可见为什么会发生这种情况

无法确定 BlogEntity 是否具有
分配的标识符
00000000-0000-0000-0000-000000000000
是短暂的或分离的;查询
数据库。使用显式 Save() 或
在会话中使用 Update() 来防止这种情况发生。

解决了我的实现IInterceptor,将其传递给Session,特别是它的方法bool? IsTransient(对象实体)

问题解决了。

Answering my own question.

The problem was that nhibernate was hiting DB to retrieve BlogEntity with id 00000000-0000-0000-0000-000000000000. Of course in DB it got nothing, so it tried to insert null

And it was clearly visible in logs why it was happening

Unable to determine if BlogEntity with
assigned identifier
00000000-0000-0000-0000-000000000000
is transient or detached; querying
the database. Use explicit Save() or
Update() in session to prevent this.

Solved it my implementing IInterceptor, passing it to Session and especially its method bool? IsTransient(object entity)

And problem solved.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文