Fluent NHibernate: foreign key field not being set in unidirectional association - nhibernate

I have a database with a ProbateCases table and a Properties table. The Properties table has a foreign key to the ProbateCases table called ProbateCaseId, so the relationship between ProbateCases and Properties is one-to-many.
My domain layer has a ProbateCase class and a Property class. The ProbateCase class has a collection of Properties defined as follows:
private IList<Property> _properties = new List<Property>();
public virtual IEnumerable<Property> Properties { get { return _properties; } }
public virtual Property AddProperty()
{
Property property = new Property();
_properties.Add(property);
return property;
}
The corresponding part of the Fluent NHibernate mapping looks like this:
HasMany(x => x.Properties).Where("Deleted = 0").KeyColumn("ProbateCaseId").Cascade.All().Access.CamelCaseField(Prefix.Underscore);
Note that the association is unidirectional - the ProbateCase class has a collection of Properties, but the Property class does not have a ProbateCase member.
I'm finding that querying works fine - NHibernate is creating the appropriate SQL to get Properties with the appropriate ProbateCaseId value.
However, when I save a ProbateCase to which I have added a new Property, the INSERT SQL does NOT contain a value for the foreign key field - so I get a SQL Exception complaining of a NULL value in the foreign key:
INSERT INTO AdminOverview.Properties (PropertyName) VALUES ('Name of property') -- Where the hell is the ProbateCaseId field value???
Should I be expecting NHibernate to populate the foreign key value itself, or is there something else I should be doing?

From http://nhibernate.info/doc/nh/en/index.html#collections-onetomany:
Very Important Note: If the column of a association is declared NOT NULL, NHibernate may cause constraint violations when it creates or updates the association. To prevent this problem, you must use a bidirectional association with the many valued end (the set or bag) marked as inverse="true". See the discussion of bidirectional associations later in this chapter.

Related

Change column name for non-primitive field (navigation) with EF Core

Given the following classes:
public class Mission
{
private MissionCard _missionCard;
}
public class MissionCard
{
}
I would like to create this relationship via Fluent API so that _missionCard is treated as a relationship and can be populated from DB but isn't available as a property on my Mission model.
I can create that relationship with:
modelBuilder.Entity<Mission>().HasOne<MissionCard>("_missionCard");
but by default this creates a FK column named "_missionCard". The docs show that a custom name can be specified when using .Property("property name").FromField("field name") but you cannot use .Property for non-primitive types.
Is it possible to change the column name for a relationship like above?
Managed to resolve this by inverting the relationship:
modelBuilder.Entity<MissionCard>()
.HasMany<Mission>()
.WithOne("_missionCard")
.HasForeignKey(nameof(MissionCard));

How to set "cascade delete" option to "Set Null" in Fluent NHibernate?

I am new to Fluent nHibernate and would like to know, if I have two classes Profile and Email mapped one-to-many as following... I want to define a nHibernate mapping fluently so when Profile is deleted, Email will remain in the DB, with a key set to Null. Or in other words to have "ON DELETE SET NULL"
ALTER TABLE [dbo].[Email] WITH CHECK ADD CONSTRAINT [FK4239B252F6539048] FOREIGN KEY([ProfileId])
REFERENCES [dbo].[Profile] ([Id])
ON UPDATE SET NULL
ON DELETE SET NULL
Any help is greately appreciated!
public sealed class ProfileMapping : ClassMap<Profile>
{
public ProfileMapping()
{
// Some other fields here ...
HasMany(x => x.Emails);
}
}
public class EmailMapping : ClassMap<Email>
{
public EmailMapping()
{
Id(x => x.Id).GeneratedBy.GuidComb();
Map(x => x.Address).Not.Nullable().UniqueKey("UX_EmailAddress").Length(254);
Map(x => x.Confirmed);
}
}
You won't be able to specify this behavior automatically in Fluent NHibernate AFAIK. Although the ON DELETE/ON UPDATE behavior specification is common to all DBs that NHibernate supports, NH/FNH control cascading with specific levels of cascade behavior:
none - do not do any cascades, let the users handles them by themselves.
save-update - when the object is saved/updated, check the assoications and save/update any object that require it (including save/update the assoications in many-to-many scenario).
delete - when the object is deleted, delete all the objects in the assoication.
delete-orphan - when the object is deleted, delete all the objects in the assoication. In addition to that, when an object is removed from the assoication and not assoicated with another object (orphaned), also delete it.
all - when an object is save/update/delete, check the assoications and save/update/delete all the objects found.
all-delete-orphan - when an object is save/update/delete, check the assoications and save/update/delete all the objects found. In additional to that, when an object is removed from the assoication and not assoicated with another object (orphaned), also delete it.
As you can see, "SET NULL" is not one of the available cascade behaviors.
The best you can do in this case is to not cascade at all, and instead to define the relationship as "Inverse" (E-mails "control" what profile they belong to; Profiles do not "own" their E-mails as such), and to implement logic either in your Repository or attached to the NHibernate Session that will remove all references of the child Emails to their parent Profile, then save all the children as "orphan" records before deleting the Profile.

Fluent NHibernate Mapping Single Column to Composite Key

I have a situation where i have defined an entity in my domain model in which I would like to expose a single id column.
public class OfferedProduct
{
public virtual string Id {get; set;}
//other properties
}
The legacy database table this will map to is
CREATE TABLE ProductGrouping
MemberNumber INT NOT NULL,
GroupId CHAR NOT NULL,
...
I dont want to compromise the domain model by introducing two properties and mapping them using the "CompositeId" construct.
CompositeId().KeyProperty(x => x.MemberNumber).KeyProperty(x => x.GroupId)
What I want ideally is to concatenate the two values in the form {MemberNumber}{GroupId} and expose this as the Id value. I would then use a Custom Type to handle how these values are concatenated when retrieved from the DB and broken apart when saving/selecting.
I have noticed that the "CompositeId" method does not allow a customType as with the standard "Id" call; but the "Id" method does not provide the ability to set multiple columns. I have seen examples where people have used "Map" to combine two columns using a custom type, but not for id values.
I have noticed the "CompositeId" has an overload that can take a custom identity class but I am unsure how to use it in this scenario.
CompositeId<OfferedProductIdentifier>(x => x.?)
Any help would be greatly appreciated.
in case someone comes here
CompositeId()
.KeyProperty(t => t.Id, c =>
c.Type(typeof(MyUserType)).ColumnName("MemberNumber").ColumnName("GroupId"));

NHibernate: Violated not-null constraint when saving HasMany relation with Cascade=AllDeleteOrphan

My bean looks like this:
public class A {
...
[HasMany (MapType = typeof(B), Table = "B_table", ColumnKey = "A_object_id",
Fetch = FetchEnum.Join,
RelationType = RelationType.List, Index = "id",
Cascade = ManyRelationCascadeEnum.AllDeleteOrphan)]
IList<B> BList { get; set; }
...
}
and when perform Save on this bean I expect that beans of type B will be automatically
saved (and deleted on update) too. NHibernate surely is trying that, but it does so
with B_table.A_object_id set to NULL first and then NHibernate updates B_table setting the proper B_table.A_object_id value (that is: A.ID).
This is not what I want, as I have a NOT NULL constraint in the database.
My question is: how to make NHibernate automatically save the child objects with the proper ID set from the start? I know I can create A bean, save it, get it's brand new ID, create B beans, set their A_object_id and then save B beans... but it's a workaround.
Unidirectional relationships (in which only the parent knows about the child) always result in an update for setting the Id. I'm not sure why and it doesn't make a lot of sense to me either but that's just how NHibernate works.
You need to create a bidirectional relationship where the HasMany would have an Inverse = true and B would have a reference to class A in it (which should be populated when you add B to the A collection.

NHibernate Parent/Child relation

I ve got the following setup:
public class ParentEntity
{
public ICollection<ChildEntity> {get; set; }
}
public class ChildEntity
{
// do i need to the parent here?
}
I managed to save the ParentEntity and cascaded the save to the added child entities which were saved as well. But in the db table the ParentId reference of the child was set to allow NULL. When setting it to NOT NULL the save failes since the ParentId in the child table is NULL.
What's happening there? ;)
When
You should map both sides of the relationship normally, and when you add a child to the parent's collection, you should also set the parent property on the child. Normally you would achieve this by writing a method like this:
public void AddChild(ChildEntity child)
{
this.Children.Add(child);
child.Parent = this;
}
NHibernate persists the ParentId column in the Child table based on the mapped property in the ChildEntity class. The definition of the one-to-many relationship merely allows NHibernate to load the collection from the database based on values in this column
I am having the same issue and need this to either have nHibernate expose the foreign key column, or do it in class via collection.
Problem: nHibernate creates the collection object (IList, for example) and you can not override the or listen to the add events of basic collections.
This becomes an issue only because it is required by the WCF RIA Services framework.