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?
Related
When I create a table in entity framework, i am not set any key in the table. But, when the table created the id field in the table set as key, Why?
public class EntityBase
{
public long Id { get; set; }
public DateTimeOffset? DeletedOn { get; set; }
public string RefId { get; set; }
public DateTimeOffset CreatedOn { get; set; }
}
As mentioned here Entity framework automatically identifies the primary key based on ideal naming like Id in your case :-
As detailed in document :-
Other default conventions supported by EF include the ability to
automatically identify primary-key and foreign keys based on common
naming patterns (for example: an ID or DinnerID property on the Dinner
class will be inferred as the primary key). EF also includes smart
conventions for wiring-up association relationships between models.
For more information :-
http://blogs.msdn.com/b/efdesign/archive/2010/06/01/conventions-for-code-first.aspx
I'm trying to figure out how to structure my entity mappings to achieve the following:
public class Document
{
public virtual string Name { get; set; }
// Other properties
public IList<Document> RelatedDocuments { get; set; }
}
I'd like to have a relationship table that has ID pairs of the related Documents.
Right now I'm addressing this problem with the solution described in this SO question: Fluent Nhibernate mapping related items (crazy coincidence that the OP's name is the same as mine).
I'd rather have a single list of related items and not have to have one for RelatedTo and one for RelatedFrom. Is that possible?
To clarify, the problem I'm looking to solve is that if I relate Document A to Document B, I need Document A's RelatedDocuments list to have Document B in it, and Document B's RelatedDocuments list to have Document A in it, without having to create two relationships.
Try something like this:
class Document
{
public int Id { get; set; }
public string Name { get; set; }
public IList<Document> Related { get; set; }
public void RelateTo(Document other)
{
this.Related.Add(other);
other.Related.Add(this);
}
}
class DocumentMap : FluentNHibernate.Mapping.ClassMap<Document>
{
public DocumentMap()
{
Table("Documents");
Id(x => x.Id);
Map(x => x.Name);
HasManyToMany(x => x.Related)
.Table("DocumentRelations")
.ParentKeyColumn("DocumentId")
.ChildKeyColumn("RelatedDocumentId");
}
}
The DocumentRelations table is the association table which specifies that RelatedDocumentId is related to DocumentId. The tables would look like:
create table Documents
(
Id int identity primary key clustered,
Name varchar(100)
)
create table DocumentRelations
(
DocumentId int,
RelatedDocumentId int,
primary key clustered (DocumentId,RelatedDocumentId)
)
You should consider whether you need to have any data associated with the relationship itself. In that case, the related collection would be a collection of RelatedDocument instances which would have the related document as a property and the mapping would be HasMany.
I got a problem with automapping in fluent and reference key. Example would be that:
public class ConfigurationCategory
{
public virtual Guid Id { get; private set; }
[NotNull]
public virtual String Name { get; set; }
public virtual String Description { get; set; }
public virtual String Icon { get; set; }
public virtual ConfigurationCategory Parent { get; set; }
public virtual IList<ConfigurationCategory> Children { get; private set; }
public ConfigurationCategory()
{
Children = new List<ConfigurationCategory>();
}
}
Results in the following SQL-Output:
CREATE TABLE "ConfigurationCategory"
...
parent_id uuid,
configurationcategory_id uuid,
CONSTRAINT "ConfigurationCategory_pkey" PRIMARY KEY (id),
CONSTRAINT fk6ccc850055890dc8 FOREIGN KEY (configurationcategory_id)
REFERENCES "ConfigurationCategory" (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION,
CONSTRAINT fk6ccc8500ee71b726 FOREIGN KEY (parent_id)
REFERENCES "ConfigurationCategory" (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
Why is ConfigurationCategory duplicated?
I haven't used fluent automapping, but I would guess it is confused by the fact that you have both the Parent and the Children properties; I would guess fluent can't tell that they are both meant to be handled by the same column in the database.
You probably need to create a ClassMap and specify the key column names for both the References() and HasMany() calls.
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 }
}
}
My automapping:
return Fluently.Configure()
.Database(config)
.Mappings(m =>
m.AutoMappings.Add(
AutoMap.AssemblyOf<Company>()
.Where(
t => t.Namespace == "DAL.DomainModel" && t.IsClass)
.IgnoreBase<ReferenceEntity>()))
.BuildSessionFactory();
So ReferenceEntity is an abstract class containing a string Name, and all my reference entities inherit from this class. I'd like to modify my automapping to add a unique constraint to the Name field for all entities that inherit from ReferenceEntity.
I've gathered it has something to do with .Setup but I'm a bit lost on how to proceed.
note: I'm using the Fluent NHibernate v1.0 RTM so conventions will be with the new style if that is relavent to my goal.
If all your entities inherit from ReferenceEntity, wouldn't you want to create the unique constraint for the Name property on all the entities that are mapped?
But if you want to filter by entity base class, you can do it. Use a convention to add the unique constraint to your mappings:
public class NameConvention : IPropertyConvention
{
public void Apply(IPropertyInstance instance)
{
// Check the entity base class type
if (instance.EntityType.BaseType.Name == "ReferenceEntity")
{
// Only add constraint to the .Name property
if (instance.Name == "Name")
{
instance.Unique();
}
}
}
}
To get the convention (and all other conventions in the assembly) picked up by FNH, just add this line the AutoMap setup you have above:
.Conventions.AddFromAssemblyOf<NameConvention>()
Alex,
No the answer doesn't change. Here is an example, using the convention above.
public abstract class ReferenceEntity
{
public virtual int Id { get; protected set; }
public virtual string Name { get; set; }
}
public class User : ReferenceEntity
{
public virtual string Email { get; set; }
}
public class Item : ReferenceEntity
{
public virtual string Description { get; set; }
}
This creates sql of:
create table Users (
Id INTEGER not null,
Email TEXT not null,
Name TEXT not null unique,
primary key (Id)
)
create table Items (
Id INTEGER not null,
Description TEXT,
Name TEXT not null unique,
primary key (Id)
)
As long as these are separate entities, it will create a unique constraint on the .Name property for each entity.