Mapping one-to-one relationship with a wrong (brownfield) database schema - nhibernate

I have to model this relationship in NHibernate (simplified the code a bit to stay on-topic) - an employee can be an accountmanager (so, it's optional):
table Employee (Id, Number, Name)
table EmployeeIsAccountManager (Number, MaxAllowedDiscount)
instead of having an Id foreign key in table EmployeeIsAccountManager pointing to table Employee, I have a Number column in the Employee table which points to the Number column in table EmployeeIsAccountManager.
How do I map this in NHibernate? I've tried using the foreign generator on the EmployeeIsAccountManager class mapping, but if I use Number as foreign generated value, it maps to the ID of Employee, which is Id instead of Number. I modeled my class to use composition:
public class Employee
{
public virtual int Id { get; set; }
public virtual short Number {get; set; }
public virtual string Name {get; set; }
public virtual AccountManager AccountManager { get; set; }
}
public class AccountManager
{
public virtual short Number { get; set; } /*needed because of ID only?*/
public virtual decimal MaxAllowedDiscount { get; set }
}
I've tried a lot (one-to-one, many-to-one, foreign generator) but I can't figure out if this can be done with NHibernate. btw: I can change the classes, mappings, etc but I CANNOT change the table structure because of it's brownfield status (old application with 2+ million lines of code, nearly 1000 forms).
Any help is appreciated, thanks!
Ted

Your question make me think about class inheritance, you could map your class AccountManager as a subclass of Employee and then you will able to do what you want to do, I'v etested a mapping for you but as you designed tables that way does not resolve your needs because there are two points you have to notice in your mapping:
The number property in the Employee table should be a unique kind of foreing key to AccountManager in order to be used as a foreign key but even so it does'mt work because NHibernate, when you try to insert a new Account Manager will insert a record in the person table and then assign the id of person to the number column of AccountManager an that break you needs.
Mapping that relation as many-to-one doesn't work for the same reason. The Number property of AccountManager is primary key? is unique? NHibernate cannot work without primary keys, so in order to make that relation to work you have to specify the Number propety of AccountManager as an Id column
The last option which comes in my mind is to use a property in the Employee class mapped
to the AccountManager table with a formula where you can specify a custom select to obtain the value you need I assume the property MaxAllowedDiscount, but this too has some limitation, when you map a property with formula, this property cannot be inserted nor updated.
Hope this helps
lat me konw if there are questions.

public class Employee
{
public virtual short Number
{
get { return (AccountManager == null) ? 0 : AccountManager.Number; }
set
{
if (AccountManager == null)
AccountManager = new AccountManager();
AccountManager.Number = value;
}
}
public virtual AccountManager AccountManager { get; set; }
}
or with GeneratedBy.Assinged()
public class Employee
{
public Employee()
{
AccountManager = new AccountManager();
}
public virtual AccountManager AccountManager
{
get;
set { value.Parent = this; _accountManager = value; }
}
public class AccountManager
{
Internal protected virtual Employee Parent { get; set; }
protected virtual short Number { get { return Parent.Number; } set { } } /*needed because of ID only?*/
public virtual decimal MaxAllowedDiscount { get; set }
}
}

Related

EF Core composite foreign key and constraint

In my project I have noticed that I will be have a lot of dictionaries with the same structure:
shortcut
full name for tooltip
which will be used on many different business forms.
I started to thing that there is no sense to keep all of them in separate tables.
It is better to keep all of them in one table and provide an additional column (DictionaryType) which will separate them in the case of asking the database for data?
So one repository with such method
public class DictionaryEntity
{
public Guid Id { get; set; }
public string Name { get; set; }
public string FullName { get; set; }
public DictionaryType Type { get; set; }
}
public async Task<IEnumerable<DictionaryEntity> GetDictionaries(DictionaryType type)
{
return await _dbContext.Dictionaries.Where(d => d.DictionaryType == type).ToArrayAsync();
}
If new dictionaries appear, I need to only extend DictionaryType and I don't need to worry about database changes or repo/service/controller changes.
For now it is nice and easy, but... I would like to configure foreign key in business entities in that way:
public class CarEntity
{
public Guid Id { get; set; }
public Guid ModelTypeId { get; set;}
public DictionaryEntity ModelType { get; set;}
public Guid PetrolTypeId { get; set;}
public DictionaryEntity PetrolType { get; set;}
}
How to configure in EF Core, foreign key in that way where:
CarEntity.ModelTypeId points to DictionaryEntity.Id and DictionaryEntity.Type = DctionaryType.ModelType ?
CarEntity.PetrolTypeId points to DictionaryEntity.Id and DictionaryEntity.Type = DctionaryType.PetrolType ?
I read, that there is something like a composite foreign key, so I could do FK on { dict.Name, dict.Type } but it demands from me to keep in CarEntity as many properties as composite foreign key have.
Is there a chance to do unique constraint across multiple tables ?
Something like this:
modelBuilder.Entity<CarEntity>()
.HasCheckConstraint("CK_ModelType", "[ModelTypeId] IS NOT NULL AND [Document].[Type] = 'ModelType'", c => c.HasName("CK_ModelType_Dictionary"));

NHibernate (Fluent) Lazy Loading Not Working

I am attempting to use NHibernate to generate a model for a very odd database. The tables themselves have primary keys for show only, all the actual relationships are on unique columns. For example, a product table with a product id primary key and a unique product name column. Another table, demand, has a product name column and that defines the relationship. I know this situation isn't ideal but it's out of my control.
At any rate, I was able to use Fluent NHibrenate to map product to demand, but I cannot seem to get the entity to lazy-load.
public class Demand
{
public virtual DemandId { get; set; }
public virtual Product { get; set; }
}
public class DemandMap : ClassMap<Demand>
{
public DemandMap()
{
this.Table("Demand");
this.LazyLoad();
this.Id(x => x.DemandId);
this.References(x => x.Product).PropertyRef(x => x.ProductName).LazyLoad();
}
}
Does anyone have any insight into why lazy loading is not working? I know it is not because I can see the product being fetched along with the demand in the SQL profiler.
My idea (Maybe you can try use "HasMany" there is example but you can read something about this):
First class
public class Demand
{
public virtual int DemandId { get; set; }
public virtual int Product { get; set; }
public virtual IEnumerable<NewClass> Name {get; set;}
}
this.HasMany(x=> x.Product).Column("Product_id").not.nullable;
Second class
public class NewClass
{
public virtual Demand Product_id {get; set;}
}
this.References(x => x.Product).Column("product_id).not.nullable

Fluent nHibernate - Wrong column name when self reference

The mapping on foreign key are made with the wrong name. Why?
Here's my classes:
The order of the properties seems to be important:
public class Person
{
public virtual Person Mother { get; set; }
public virtual IList<Item> Items { get; set; }
public virtual Person Father { get; set; }
}
public class Item
{
public virtual string Name { get; set; }
}
Here's the mapping with Fluent Nhibernate
AutoMap.AssemblyOf<Person>(new CustomAutomappingConfiguration())
When I look to the database, the foreign key in the table seems to be the name of the first property with the type Person after the property Items. Here's the SQL generated to create the table:
CREATE TABLE "Item" (Id integer primary key autoincrement
, Name TEXT
, Father_id BIGINT
, constraint FKC57C4A2B4586680 foreign key (Father_id) references Patient)
Thank you in advance for your help ;)
The solution I've found is to override the configuraton like this:
AutoMap.AssemblyOf<Person>(new CustomAutomappingConfiguration())
.Override<Person>(m => m.HasMany<Item>(x => x.Items).KeyColumn("Patient_Id"))
Does exist any solution to let the auto mapping work seamlessly? And how Fluent nHibernate works to choose the name of the foreign key's column?

Fluent NHibernate one-to-many with intervening join table?

I'm having trouble getting the Fluent Nhibernate Automapper to create what I want. I have two entities, with a one-to-many relationship between them.
class Person
{
public string name;
IList<departments> worksIn;
}
class Department
{
public string name;
}
The above is obviously bare bones, but I would be expecting to generate the fleshed out schema of:
Person{id, name}
Department{id, name}
PersonDepartment{id(FK person), id(Fk Department)}
Unfortunately, I am instead getting:
Person{id, name}
Department{id, name, personid(FK)}
I don't want the FK for Person included on the department table, I want a separate join/lookup table (PersonDepartment above) which contains the primarykeys of both tables as a composite PK and also Fks.
I'm not sure if I am drawing up my initial classes wrong (perhaps should just be LIst workIn - representing ids, rather than List worksIn), or if I need to manually map this?
Can this be done?
The way the classes have been structured suggests a one-to-many relationship (and indeed that's how you describe it in your question), so it should not be a surprise that FNH opts to model the database relationship in that way.
It would be possible, as you suggest, to manually create a many-to-many table mapping. But, is this definitely what you want?
I tend to find that pure many-to-many relationships are quite rare, and there is usually a good case for introducing an intermediate entity and using two one-to-many relationships. This leaves open the possibility of adding extra information to the link (e.g. a person's "primary" department, or perhaps details of their office within each of their departments).
Some example "bare-bones" classes illustrating this kind of structure:
public class Person
{
public int Id { get; set;}
public string Name { get; set;}
public IList<PersonDepartment> Departments { get; set; }
}
public class PersonDepartment
{
public int Id { get; set; }
public Person Person { get; set; }
public Department Department { get; set; }
public bool IsPrimary { get; set; }
public string Office { get; set; }
}
public class Department
{
public int Id { get; set; }
public IList<PersonDepartment> Personnel { get; set; }
public string Name { get; set; }
}

Fluent NHibernate Mapping not on PK Field

I have the following tables and cannot edit their structure...
Person
------
Id PK
Code
Name
Order
-----
Id PK
Person_Code
OrderDetails
Now in my Person class I want to have a list of Orders for that person, but I'm not entirely sure how to go about setting up the mapping in fluent nhibernate to match on the Code column rather than the ID. There is no foreign key constraint and I am unable to change the database to use the keys. Something like this is what I require, but can;t seem to figure out the mapping.
public class Person
{
public virtual int Id { get; set; }
public virtual string Code { get; set; }
public virtual IList<Order> Orders { get; private set; }
}
public class Order
{
public virtual int Id { get; set; }
public virtual string OrderDetails { get; set; }
public virtual Person Owner { get; set; }
}
You define your column with the KeyColumn method. It should work regardless of existence of a foreign key constraint.
class PersonMap : ClassMap<Person>
{
public PersonMap()
{
HasMany(p => p.Order)
.KeyColumn("Person_Code")
.PropertyRef("Code");
}
}
PropertyRef method is available from rev 614 so you may need to update the fluent nhibernate version.