What HBM do I have to write for Blog
and Post
to have a bidirectional relationship between these tables?
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
andPost
tables referencing each other.
Note: My example is contrived, please don't argue the design.
Design:
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.
精彩评论