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.
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
WebOptionsI removed this single line:for a constructor that looks like this:
Then, I save only my
WebOptionsobject 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
Sitein addition to setting theSite.WebOptionsproperty, 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.