I've got a Problem wiht my nHibernate Mapping-By-Code.
Table Content
has multiple Entries from Table Content_Texts
referenced by FK Column "ContentId".
If I'm adding a new ContentEntry
with one Text in the collection i get the first Query to the Content Table executed but the second one (to Content_Texts) fails because NHibernate is trying to insert an Content_Text Entity with ContentId = 0, that doesn't exist for sure in the Content Table.
Here is my Mapping for the Content Table:
public class ContentMap : ClassMapping<TContent>
{
#region Constructors
public ContentMap()
{
Table("nfcms_Content");
Schema("dbo");
Lazy(false);
Id<int>(x => x.Id, map => {
map.Generator(Generators.Identity);
});
//Property(x => x.Id, map => map.NotNullable(true));
Property(x => x.Cid, map =>
{
map.NotNullable(false);
});
Property(x => x.CreatorPKID, map => map.NotNullable(false));
Property(x => x.Locked, map => {
map.NotNullable(true);
map.Type(NHibernateUtil.Boolean);
});
Property(x => x.RatingGroupID);
Property(x => x.CDate);
Property(x => x.ContentType, map => map.NotNullable(true));
Property(x => x.ContentRef);
Property(x => x.CreatorSpecialName);
Bag(x => x.Texts, mapping =>
{
mapping.Lazy(CollectionLazy.NoLazy);
mapping.Key(k =>
{
k.Column("ContentId");
});
mapping.Inverse(true);
mapping.Cascade(Cascade.All);
mapping.Fetch(CollectionFetchMode.Select);
},
r => r.OneToMany());
ManyToOne(x => x.User, m =>
{
m.Column(c => c.Name("CreatorPKID"));
m.Fetch(FetchKind.Select);
m.Cascade(Cascade.None);
m.Insert(false);
m.Update(false);
m.Lazy(LazyRelation.NoLazy);
});
ManyToOne(x => x.Category, m =>
{
m.Column(c => c.Name("CID"));
m.Fetch(FetchKind.Select);
m.Cascade(Cascade.None);
m.Insert(false);
m.Update(false);
m.Lazy(LazyRelation.NoLazy);
});
//OneToOne(x => x.Category, map =>
//{
// map.PropertyReference(
// map.Column("CID");
// map.NotFound(NotFoundMode.Ignore);
// map.Cascade(Cascade.None);
//});
//ManyToOne(x => x.User, map =>
//{
// map.PropertyRef("PKID");
// map.Column("CreatorPKID");
// map.Cascade(Cascade.None);
//});
}
#endregion Constructors
}
And Here for the Content_Text Table
public class ContentTextMap : ClassMapping<Persistence.Domain.ContentText>
{
#region Constructors
public ContentTextMap()
{
Table(Ren.CMS.CORE.Config.RenConfig.DB.Prefix +"Content_Text");
Schema("dbo");
Lazy(false);
Id<int>(x => x.Id, map => {
map.Generator(Generators.Identity);
});
Property(x => x.ContentId, map => map.NotNullable(true));
Property(x => x.LangCode, map => map.NotNullable(true));
//Property(x => x.Id, map => map.NotNullable(true));
Property(x => x.Title, map => map.NotNullable(true));
Property(x => x.Seoname);
Property(x => x.MetaKeyWords);
Property(x => x.MetaDescription);
Property(x => x.PreviewText);
Property(x => x.LongText, x => x.Type(NHibernateUtil.StringClob));
//OneToOne(x => x.Category, map =>
//{
// map.PropertyReference(
// map.Column("CID");
// map.NotFound(NotFoundMode.Ignore);
// map.Cascade(Cascade.None);
//});
//ManyToOne(x => x.User, map =>
//{
// map.PropertyRef("PKID");
// map.Column("CreatorPKID");
// map.Cascade(Cascade.None);
//});
}
#endregion Constructors
}
This are the executed queries from NHibernate:
NHibernate: INSERT INTO dbo.nfcms_Content (CDate, Cid, ContentRef, ContentType, CreatorPKID, CreatorSpecialName, Locked, RatingGroupID) VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7); select SCOPE_IDENTITY();@p0 = 27.10.2014 13:51:58 [Type: DateTime (0)], @p1 = NULL [Type: Guid (0)], @p2 = 0 [Type: Int32 (0)], @p3 = 'eNews' [Type: String (4000)], @p4 = NULL [Type: Guid (0)], @p5 = '' [Type: String (4000)], @p6 = False [Type: Boolean (0)], @p7 = 0 [Type: Int32 (0)]
NHibernate: INSERT INTO dbo.nfcms_Content_Text (ContentId, LangCode, LongText, MetaDescription, MetaKeyWords, PreviewText, Seoname, Title) VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7); select SCOPE_IDENTITY();@p0 = 0 [Type: Int32 (0)], @p1 = 'de-DE' [Type: String (4000)], @p2 = 'Test' [Type: String (1073741823)], @p3 = 'test' [Type: String (4000)], @p4 = 'test' [Type: String (4000)], @p5 = 'test' [Type: String (4000)], @p6 = 'TEST123455' [Type: String (4000)], @p7 = 'TEST' [Type: String (4000)]
Can anyone tell me what's wrong? I searched and searched and got to no soulution...
Because we do have one-to-many
relation end mapped as a Bag
with inverse setting (which is absolutely ok) like this:
public ContentMap()
{
...
Bag(x => x.Texts, mapping =>
{
mapping.Lazy(CollectionLazy.NoLazy);
mapping.Key(k =>
{
k.Column("ContentId");
});
...
We need the other end - the many-to-one as well. In our case it must be represented by reference Content
(and could be also expressed as readonly int
ContentId value)
public ContentTextMap()
{
ManyToOne(x => x.Content, "ContentId");
Property(x => x.ContentId, map => {
map.Column("ContentId");
map.Update(true);
map.Insert(true);
map.NotNullable(true)
});
...
Expecting POCOs like this:
public class Content
{
public virtual IList<ContentText> Texts { get; set; }
...
public class ContentText
{
public virtual Content Content { get; set; }
public virtual int ContentId { get; set; }
...
And this must be the assignment (both ends must be assigned)
var content = ...;
var contentText = ...;
content.Texts.Add(contentText);// both ends must be assigned
contentText.Content = content; // both ends must be assigned