Nhibernate:一对多映射问题 - 无法级联删除而无需逆向。设置 NULL 错误
我目前的情况是,每篇文章只有 1 个结果。每篇文章可能有也可能没有结果。
理论上,这是一对一的映射,但是由于NHibernate并不真正支持一对一,所以我使用了一对多来替代。我在子表上的主键实际上是ArticleID (FK)。
所以我有以下设置:
类
public class Article
{
public virtual Int32 ID { get;set;}
private ICollection<ArticleOutcome> _Outcomes {get;set;}
public virtual ArticleOutcome Outcome
{
get {
if( this._Outcomes !=null && this._Outcomes.Count > 0 )
return this._Outcomes.First();
return null;
}
set {
if( value == null ) {
if( this._Outcomes !=null && this._Outcomes.Count > 0 )
this._Outcomes.Clear();
}
else {
if( this._Outcomes == null )
this._Outcomes = new HashSet<ArticleOutcome>();
else if ( this._Outcomes.Count >= 1 )
this._Outcomes.Clear();
this._Outcomes.Add( value );
}
}
}
}
public class ArticleOutcome
{
public virtual Int32 ID { get;set; }
public virtual Article ParentArticle { get;set;}
}
映射
public class ArticleMap : ClassMap<Article>
{
public ArticleMap() {
this.Id( x=> x.ID ).GeneratedBy.Identity();
this.HasMany<ArticleOutcome>( Reveal.Property<Article>("_Outcomes") )
.AsSet().KeyColumn("ArticleID")
.Cascade.AllDeleteOrphan() //Cascade.All() doesn't work too.
.LazyLoad()
.Fetch.Select();
}
}
public class ArticleOutcomeMap : ClassMap<ArticleOutcome>
{
public ArticleOutcomeMap(){
this.Id( x=> x.ID, "ArticleID").GeneratedBy.Foreign("ParentArticle");
this.HasOne( x=> x.ParentArticle ).Constrained ();
//This do not work also.
//this.References( x=> x.ParentArticle, "ArticleID" ).Not.Nullable();
}
}
现在我的问题是这样的:
当我插入/更新结果时它起作用。 例如,
var article = new Article();
article.Outcome = new ArticleOutcome { xxx = "something" };
session.Save( article );
但是,当我尝试通过文章本身删除时,我遇到了 SQL 错误。
var article = session.Get( 123 );
session.Delete( article ); //throws SQL error.
该错误类似于无法将 NULL 插入 ArticleOutcome 表中的 ArticleID。
如果我将 Inverse() 放置到文章的 HasMany() 映射中,则删除有效,但插入将会失败。
有人有解决方案吗?或者我真的必须向 ArticleOutcome 表添加代理键吗?
解决方案
如果有人感兴趣的话,这是 Fluent 的映射。
public class ArticleMap : ClassMap<Article>
{
public ArticleMap() {
this.Id( x=> x.ID ).GeneratedBy.Identity();
this.HasOne( x=> x.Outcome ).Cascade.All();
}
}
public class Article
{
//... other properties
public virtual ArticleOutcome Outcome { get;set;}
}
I have the current scenario whereby an Article has only 1 Outcome each. Each Article may or may not have an Outcome.
In theory, this is a one-to-one mapping, but since NHibernate does not really support one-to-one, I used a One-To-Many to substitute. My Primary Key on the child table is actually the ArticleID (FK).
So I have the following setup:
Classes
public class Article
{
public virtual Int32 ID { get;set;}
private ICollection<ArticleOutcome> _Outcomes {get;set;}
public virtual ArticleOutcome Outcome
{
get {
if( this._Outcomes !=null && this._Outcomes.Count > 0 )
return this._Outcomes.First();
return null;
}
set {
if( value == null ) {
if( this._Outcomes !=null && this._Outcomes.Count > 0 )
this._Outcomes.Clear();
}
else {
if( this._Outcomes == null )
this._Outcomes = new HashSet<ArticleOutcome>();
else if ( this._Outcomes.Count >= 1 )
this._Outcomes.Clear();
this._Outcomes.Add( value );
}
}
}
}
public class ArticleOutcome
{
public virtual Int32 ID { get;set; }
public virtual Article ParentArticle { get;set;}
}
Mappings
public class ArticleMap : ClassMap<Article>
{
public ArticleMap() {
this.Id( x=> x.ID ).GeneratedBy.Identity();
this.HasMany<ArticleOutcome>( Reveal.Property<Article>("_Outcomes") )
.AsSet().KeyColumn("ArticleID")
.Cascade.AllDeleteOrphan() //Cascade.All() doesn't work too.
.LazyLoad()
.Fetch.Select();
}
}
public class ArticleOutcomeMap : ClassMap<ArticleOutcome>
{
public ArticleOutcomeMap(){
this.Id( x=> x.ID, "ArticleID").GeneratedBy.Foreign("ParentArticle");
this.HasOne( x=> x.ParentArticle ).Constrained ();
//This do not work also.
//this.References( x=> x.ParentArticle, "ArticleID" ).Not.Nullable();
}
}
Now my problem is this:
It works when I do an insert/update of the Outcome.
e.g.
var article = new Article();
article.Outcome = new ArticleOutcome { xxx = "something" };
session.Save( article );
However, I encounter SQL errors when attempting to delete via the Article itself.
var article = session.Get( 123 );
session.Delete( article ); //throws SQL error.
The error is something to the like of Cannot insert NULL into ArticleID in ArticleOutcome table.
The deletion works if I place Inverse() to the Article's HasMany() mapping, but insertion will fail.
Does anyone have a solution for this? Or do I really have to add a surrogate key to the ArticleOutcome table?
Solution
Here's the mapping for Fluent if anyone is interested.
public class ArticleMap : ClassMap<Article>
{
public ArticleMap() {
this.Id( x=> x.ID ).GeneratedBy.Identity();
this.HasOne( x=> x.Outcome ).Cascade.All();
}
}
public class Article
{
//... other properties
public virtual ArticleOutcome Outcome { get;set;}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
NHibernate 确实支持一对一。
我有一个案例和你的情况非常相似。以下是相关部分:
映射(抱歉,我不使用 Fluent,但翻译起来应该不难):
用法:
删除应该像您现在使用的那样工作。
NHibernate does support one-to-one.
I have a case very similar to yours. Here are the relevant parts:
Mapping (sorry, I don't use Fluent, but it shouldn't be hard to translate):
Usage:
Delete should work as you are using it now.