I have a Parent-Children relation and currently, only a reference from each child to the parent exists (there is a foreign key column on the child table). I would like to add a readonly IEnumerable property to the parent, but I am failing to do so.
public class ProjectData : Entity
{
public virtual long Id {get;set;}
private readonly IList<BranchData> _branches = new List<BranchData>();
public virtual IEnumerable<BranchData> Branches
{
get { return _branches.AsReadOnly(); }
}
}
public class BranchData : Entity
{
puplic virtual long Id {get;set;}
public virtual ProjectData ProjectData { get; set; }
}
public class BranchDataMapping : ClassMapping<BranchData>
{
public BranchDataMapping()
{
ManyToOne(x => x.ProjectData, mapper => { });
}
}
public class ProjectDataMapping : ClassMapping<ProjectData>
{
public ProjectDataMapping()
{
Bag(data => data.Branches,
mapper =>
{
mapper.Access(Accessor.ReadOnly);
mapper.Inverse(false);
}, relation => relation.OneToMany());
}
}
Table- and column-names are created by conventions. When I create and save a new BranchDate with parent-property set, it does not appear in the Branches collection of the parent.
What setting am I missing?
I have read Bi-directional NHibernate mapping by code and http://notherdev.blogspot.cz/2012/02/nhibernates-mapping-by-code-summary.html and I am still failing to set it properly.
Edit: Code that verifies this behaviour
[Test]
public void CanSaveAndLoadBranch()
{
var session = InMemoryDatabase.GetSession();
var project = new ProjectData {Name = "ratata"};
var branch = new BranchData {ProjectData = project};
using (var tx = session.BeginTransaction())
{
session.Save(project);
session.Save(branch);
tx.Commit();
}
var branches = project.Branches;
//branches are empty
var freshProject = session.Query<ProjectData>().Where(x => x.Id == project.Id).First();
var freshBranches = freshProject.Branches;
//branches are empty here, too
var fetched = session.Query<ProjectData>().Where(x => x.Id == project.Id).FetchMany(x => x.Branches).First();
var fetchedBranches = fetched.Branches;
//branches are empty here, too
var queriedOn = session.Query<ProjectData>().Where(x => x.Branches.Any()).ToList();
//this does return the project, but Branches property is still empty
}
When manipulating the data in-memory, you are responsible for managing both sides of the relationship. You can do this easily with an
Add
method inProjectData
:On the other side, NHibernate is responsible for properly hydrating and dehydrating your objects. However, you aren't seeing this because your queries are all occurring within the same session. Consider this code:
This code will display "They're the same instance." That instance will still have the relationships set up exactly as you initialized them, correct or not.
If you neglect to set the relationship on the inverse side,
project.Branches
, NHibernate will still be able to save it fine, but it will still continue to look inconsistent for the duration of that session. If you close the session and open a new one (this might be problematic for your in-memory test), or just callsession.Clear()
orsession.Evict(project)
, then you will see data inproject.Branches
when you load it again.