开发者

NHibernate many-to-one and bidirectional access

开发者 https://www.devze.com 2023-02-15 04:44 出处:网络
What HBM do I have to write for Blog and Post to have a bidirectional relationship between these tables?

What HBM do I have to write for Blog and Post to have a bidirectional relationship between these tables?

I tried many-to-one from both sides but run into the following problems (most likely because I did it totally wrong):

  • Transient persistance errors inserting the object graph in one Session.
  • Foreign key issues with the Blog and Post tables referencing each other.

Note: My example is contrived, please don't argue the design.

Design:

NHibernate many-to-one and bidirectional access

Source:

public class Blog
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    public virtual Comment LastComment { get; set; }  // last-comment

    public virtual IList<Post> Posts { get; set; }
}

public class Post
{
    public virtual int Id { get; set; }
    public virtual string Content { get; set; }

    public virtual IList<Comment> Comments { get; set; }
}

public class Comment
{
    public virtual int Id { get; set; }
    public virtual string Feedback { get; set; }
    public virtual Blog Blog { get; set; } //commented-on
}

HBM:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Sample" 
 namespace="Sample">
  <class name="Blog">
    <id name="Id">
      <generator class="hilo" />
    </id>
    <property name="Name" />
    <!-- How to map Comment? -->
    <bag name="Posts">
      <key column="BlogId" />
      <one-to-many class="Post" />
    </bag>
  </class>

  <class name="Post">
    <id name="Id">
      <generator class="hilo" />
    </id>
    <property name="Feedback" />
    <bag name="Comments">
      <key column="PostId" />
      <one-to-many class="Comment" />
    </bag>
  </class>

  <class name="Comment">
    <id name="Id">
      <generator class="hilo" />
    </id>
    <property name="Comment" />
    <!-- How to map back to Blog? -->
  </class>
</hibernate-mapping>

Required DB structure:

+------------------------------+
| Blog                         |
+--------------+---------------+
| Id           | int           |
| Name         | nvarchar(50)  |
| LastCommentId| int (null)    |
+--------------+---------------+

+------------------------------+
| Post                         |
+--------------+---------------+
| Id           | int           |
| BlogId       | int           |
+--------------+---------------+

+------------------------------+
| Comment                      |
+--------------+---------------+
| Id           开发者_如何学编程| int           |
| PostId       | int           |
| BlogId       | int (not-null)|
| Feedback     | nvarchar(200) |
+--------------+---------------+


You need to add a Blog property to Post if it needs to be not-null (see the last paragraph in 6.4. One-To-Many Associations)

Here are some mappings that should work:

<class name="Blog" dynamic-update="true">
  <id name="Id">
    <generator class="..."/>
  </id>
  <property name="Name" />
  <many-to-one name="LastComment" column="LastCommentId" cascade="all" />
  <bag name="Posts" cascade="all" inverse="true">
    <key column="BlogId" />
    <one-to-many class="Post" />
  </bag>
</class>
<class name="Post">
  <id name="Id">
    <generator class="..."/>
  </id>
  <property name="Content" />
  <many-to-one name="Blog" column="BlogId" />
  <bag name="Comments" inverse="true">
    <key column="PostId" />
    <one-to-many class="Comment" />
  </bag>
</class>
<class name="Comment">
  <id name="Id">
    <generator class="..."/>
  </id>
  <property name="Feedback" />
  <many-to-one name="Blog" column="BlogId" not-null="true" cascade="all" />
</class>

Then you'll be able to use code like the following:

using (var session = sessionFactory.OpenSession())
using (var tx = session.BeginTransaction())
{
    var blog = new Blog { Name = "My Blog" };
    var post = new Post { Blog = blog, Content = "My First Post" };
    var comment = new Comment { Blog = blog, Feedback = "Awesome!" };
    blog.LastComment = comment;
    blog.Posts = new List<Post> { post };
    post.Comments = new List<Comment> { comment };
    session.Save(comment);
    tx.Commit();
}

This inserts the Blog, then the Post, then the Comment, then it updates the Blog to set the LastCommentId.

Note that you need to call Save on the Comment; anything else will fail.

0

精彩评论

暂无评论...
验证码 换一张
取 消