无法以一对一关系保存新对象

发布于 2024-12-04 17:10:06 字数 3486 浏览 0 评论 0原文

我正在使用这篇文章在我的两个对象 - SiteWebOptions 之间建立一对一的关系。网站已经存在。 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 技术交流群。

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

发布评论

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

评论(1

阳光的暖冬 2024-12-11 17:10:06

哇,我花了所有的时间把它们放在一起,然后在玩弄它时,我删除了一行代码 - 只是为了看看会发生什么。

WebOptions 的构造函数中,我删除了这一行:

SiteId = site.SiteId;

对于如下所示的构造函数:

public WebOptions(Site site)
{
    Site = site;
}

然后,我只保存我的 WebOptions 对象,如下所示:

optionsRepository.Save(options);

我最好的猜测是,因为我在 Fluent 中使用“SiteId”属性的 ID 字段,Fluent 不允许我手动设置该值。除了设置 Site.WebOptions 属性之外,设置私有属性 Site 还必须为 Fluent/nhibernate 设置一对一关系,以推断要放入的值SiteId 字段。

进一步检查上面发布的文章表明,这是必须这样做的。我只是碰巧错过了这个非常重要的信息:

每当您想要为客户端分配一些饮食习惯时,您都会在代码中使用带有 Client 参数的公共构造函数,例如:<代码>AlimentaryHabits = new AlimentaryHabits(this);。 protected 构造函数由 NHibernate 内部使用,并且必须存在。你可以完全忽略它。

如果其他人遇到这个问题,我将留下这篇文章并回答,我可以为他们节省一点时间和挫败感。

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:

SiteId = site.SiteId;

for a constructor that looks like this:

public WebOptions(Site site)
{
    Site = site;
}

Then, I save only my WebOptions object like this:

optionsRepository.Save(options);

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 the Site.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:

The public constructor, taking a Client parameter, is the one you will use in your code whenever you want to assign a client some alimentary habits, such as: AlimentaryHabits = new AlimentaryHabits(this);. The protected constructor is used internally by NHibernate, and must be present. You can completely ignore it.

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.

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