Shouldn't my nhibernate mapping take care of this? Error: not-null property reference a null or transient value
I have a database with 3 tables:
- Project
- Sponsor
- ProjectSponsor
In my domain objects, i have an object Project which has a child property called Sponsors which is a list of ProjectSponsor objects, like this:
IList<ProjectSponsor> Sponsors;
here is the Nhibernate Mapping code:
ProductMap:
HasMany(x => x.Sponsors).AsBag().Inverse().Cascade.AllDeleteOrphan();
ProductSponsorMap:
References(x => x.Project).Not.Nullable();
References(x => x.Sponsor).Not.Nullable();
here is my Domain Objects:
public class Project
{
public virtual IList<Proje开发者_StackOverflow中文版ctSponsor> Sponsors { get; set; }
}
public class ProjectSponsor
{
public virtual Project Project { get; set; }
public virtual Sponsor Sponsor { get; set; }
}
ok . . now to my issue, when i try to add new Projects (with their associated projectsponsor) into the database.
Here is my code:
foreach (Project project in newProjects)
{
Repository.Save(project);
foreach (ProjectSponsor projectSponsor in project.Sponsors)
{
Repository.Save(projectSponsor);
}
}
I am getting an exception on this line:
Repository.Save(projectSponsor);
saying that not-null property reference a null or transient value is trying to be saved:
projectSponsor.Project is the property that its complaining about. I would have thought that would be set by default based on the nhibernate mapping.
do i really need to have an explicit piece of code that have this code:
projectSponsor.Project = project
or is there anything wrong with my mapping files ?
If you haven't set the projectSponsor.Project
property (and no code here says you have) then it will have the default value of null which will violate the mapping condition you've placed.
NHibernate is just going to reflect the state of the objects and the state of the objects is - for want of a better word - broken as is. You could remove the Project property on the ProjectSponsor map and all would be well but you're losing functionality to do so because obviously the directionality of relationships in OO is the reverse of RDBM directionality.
I would expect something like:
public class ProjectSponsor
{
// This is how you instantiate me!
public ProjectSponsor(Project project, Sponsor sponsor)
{
this.Project = project;
this.Sponsor = sponsor;
}
protected ProjectSponsor()
{
// I exist for NHibernates benefit only!
}
public virtual Project Project { get; set; }
public virtual Sponsor Sponsor { get; set; }
}
You should map this as a many-to-many relationship. To do this, delete ProjectSponsor from the model and map the collections using HasManyToMany. For the project map:
HasManyToMany(X => x.Sponsors).Table("ProjectSponsor")
.ParentKeyColumn("ProjectId").ChildKeyColumn("SponsorId")
.AsBag().LazyLoad();
and similarly for Sponsor:
HasManyToMany(X => x.Projects).Table("ProjectSponsor")
.ParentKeyColumn("SponsorId").ChildKeyColumn("ProjectId")
.Inverse().AsBag().LazyLoad();
Note that I marked Sponsor as the inverse side of the relationship but it could be Project. With these changes you just need to add a Sponsor to the Project's Sponsor collection for it to be persisted. I recommend exposing an AddSponsor method rather than accessing the collection directly.
However, I think you've got another problem. It appears to me that you're following the anti-pattern of having your repository classes control the ISession. One of (the many) reasons this is a bad pattern is that your saves appear to be executed immediately instead of in a transaction.
精彩评论