无法以一对一关系保存新对象
我正在使用这篇文章在我的两个对象 - Site
和 WebOptions
之间建立一对一的关系。网站已经存在。 WebOptions 中的记录可能存在也可能不存在。如果是这样,我的映射工作正常。如果不是,我的系统在尝试创建新记录时就会崩溃。
这是我的站点类(重要的部分)
public class Site : CoreObjectBase
{
public virtual int SiteId { get; set; }
public virtual WebOptions WebOptions { get; set; }
}
这是我的 Web 选项类(再次重要的部分)
public class WebOptions : CoreObjectBase
{
public virtual int WebOptionsId { get; set; }
private int SiteId { get; set; }
private Site Site { get; set; }
}
Site
的映射是
HasOne<WebOptions>(x => x.WebOptions)
.Cascade.All();
WebOptions
的映射
Id(Reveal.Property<WebOptions>("SiteId")).GeneratedBy.Foreign("Site");
HasOne<Site>(Reveal.Member<WebOptions, Site>("Site"))
.Constrained()
.ForeignKey();
在数据中,Site 后面的表没有 WebOptions 的外键字段,但 WebOptions 后面的表包含 SiteId。在我的代码中,我已经获取了该网站并使用 site.WebOptions.SomeSetting
并且希望保持这种状态。
我的问题是这样的。如果我完全偏离此映射,我的模型就会中断,并且不会返回任何 weboptions,同时会将多个记录保存到 weboptions 表中(重复项)。但是,当我尝试保存新的 WebOptions
对象时,我得到
批量更新从更新中返回了意外的行数;实际行 计数:0;预期:1
我有一个带有 2 个保存方法的存储库类:
public sealed class Repository<T> : IRepository<T> where T : CoreObjectBase
{
public void SaveWithDependence<K>(T entity, K dependant) where K : CoreObjectBase
{
entity.Validate();
dependant.Validate();
using (ITransaction tx = Session.BeginTransaction())
{
Session.SaveOrUpdate(entity);
Session.SaveOrUpdate(dependant);
tx.Commit();
}
}
public void Save(T entity)
{
entity.Validate();
using (ITransaction tx = Session.BeginTransaction())
{
Session.SaveOrUpdate(entity);
tx.Commit();
}
}
}
当找不到 WebOptions
时,我在创建一个新的时执行此操作:
var options = site.WebOptions;
if (options == null)
{
options = new WebOptions(site);
site.WebOptions = options;
}
并且构造函数看起来像这样设置私有变量
public WebOptions(Site site)
{
Site = site;
SiteId = site.SiteId;
}
,然后保存,我尝试执行以下操作:
siteRepository.Save(site);
和
siteRepository.SaveWithDependence(site, options);
和
optionsRepository.Save(options);
全部
optionsRepository.SaveWithDependence<Site>(options, site);
返回上述错误。我的会话声明看起来像这样,
sessionFactory =
Fluently.Configure().Database(
FluentNHibernate.Cfg.Db.MsSqlConfiguration.MsSql2005.DefaultSchema("dbo")
.ConnectionString(c => c
.FromConnectionStringWithKey("MyDatabase"))
.AdoNetBatchSize(20))
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<SessionManager>())
.ExposeConfiguration(x => x.SetProperty("current_session_context_class", "managed_web"))
.BuildSessionFactory();
如果不存在,我确实需要能够保存新的 WebOptions
记录,但我似乎无法让它与我的一对一一起使用关系。
I am using this article to make a one-to-one relationship between my two objects - Site
and WebOptions
. Site is already present. a record in WebOptions may or may not be present. When it is, my mappings work fine. When it is not, my system blows up trying to create a new record.
Here is my site class (the important bits)
public class Site : CoreObjectBase
{
public virtual int SiteId { get; set; }
public virtual WebOptions WebOptions { get; set; }
}
And here is my web options class (important parts again)
public class WebOptions : CoreObjectBase
{
public virtual int WebOptionsId { get; set; }
private int SiteId { get; set; }
private Site Site { get; set; }
}
And the mapping for Site
is
HasOne<WebOptions>(x => x.WebOptions)
.Cascade.All();
And the mapping for WebOptions
is
Id(Reveal.Property<WebOptions>("SiteId")).GeneratedBy.Foreign("Site");
HasOne<Site>(Reveal.Member<WebOptions, Site>("Site"))
.Constrained()
.ForeignKey();
In the data, the table behind Site has no foreighn key field to WebOptions, but the table behind WebOptions contains the SiteId. In my code, I am already getting the site and use site.WebOptions.SomeSetting
and would like to keep it that way.
My problem is this. If I deviate from this mapping at all, my model breaks and no weboptions are returned while several records are saved into the weboptions table (duplicates). But, when I try to save a new WebOptions
object, I get
Batch update returned unexpected row count from update; actual row
count: 0; expected: 1
I have a repository class with 2 save methods:
public sealed class Repository<T> : IRepository<T> where T : CoreObjectBase
{
public void SaveWithDependence<K>(T entity, K dependant) where K : CoreObjectBase
{
entity.Validate();
dependant.Validate();
using (ITransaction tx = Session.BeginTransaction())
{
Session.SaveOrUpdate(entity);
Session.SaveOrUpdate(dependant);
tx.Commit();
}
}
public void Save(T entity)
{
entity.Validate();
using (ITransaction tx = Session.BeginTransaction())
{
Session.SaveOrUpdate(entity);
tx.Commit();
}
}
}
When no WebOptions
is found, I am doing this when making a new one:
var options = site.WebOptions;
if (options == null)
{
options = new WebOptions(site);
site.WebOptions = options;
}
And the constructor looks like this to set the private variables
public WebOptions(Site site)
{
Site = site;
SiteId = site.SiteId;
}
And then to save, I have tried to following:
siteRepository.Save(site);
and
siteRepository.SaveWithDependence(site, options);
and
optionsRepository.Save(options);
and
optionsRepository.SaveWithDependence<Site>(options, site);
All of them return the above error. My session declaration looks like this
sessionFactory =
Fluently.Configure().Database(
FluentNHibernate.Cfg.Db.MsSqlConfiguration.MsSql2005.DefaultSchema("dbo")
.ConnectionString(c => c
.FromConnectionStringWithKey("MyDatabase"))
.AdoNetBatchSize(20))
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<SessionManager>())
.ExposeConfiguration(x => x.SetProperty("current_session_context_class", "managed_web"))
.BuildSessionFactory();
I really need to be able to save a new WebOptions
record if one doesn't exist, but I can't seem to get it to work with my one-to-one relationship.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
哇,我花了所有的时间把它们放在一起,然后在玩弄它时,我删除了一行代码 - 只是为了看看会发生什么。
在
WebOptions
的构造函数中,我删除了这一行:对于如下所示的构造函数:
然后,我只保存我的
WebOptions
对象,如下所示:我最好的猜测是,因为我在 Fluent 中使用“SiteId”属性的 ID 字段,Fluent 不允许我手动设置该值。除了设置
Site.WebOptions
属性之外,设置私有属性Site
还必须为 Fluent/nhibernate 设置一对一关系,以推断要放入的值SiteId 字段。进一步检查上面发布的文章表明,这是必须这样做的。我只是碰巧错过了这个非常重要的信息:
如果其他人遇到这个问题,我将留下这篇文章并回答,我可以为他们节省一点时间和挫败感。
Wow, I spent all that time putting that together and then in playing around with it, I removed one line of code - just to see what would happen.
In the constructor for
WebOptions
I removed this single line:for a constructor that looks like this:
Then, I save only my
WebOptions
object like this:My best guess is that since I am using an ID field for the 'SiteId' property in fluent, fluent doesn't allow me to manually set that value. Setting the private property
Site
in addition to setting theSite.WebOptions
property, must set up the one-to-one relationship for fluent/nhibernate to deduce what value to place into the SiteId field.Further inspection of the article posted above shows that this is the way it has to be done. I just happened to miss this very important piece of information:
I am going to leave this post and answer in the event someone else has this issue and I can save them a little bit of time and frustration.