How to change FK Name in fluent nhibernate - fluent-nhibernate

I am wondering how do I change the name of a FK with fluent nhibernate.
Right now it makes all the foreign keys like (product_id,student_id) what is find but there is one table I want it to have a different name.
I want the courses table to have for the foreign key "MyFKName" but it keeps generating "student_id"
public CourseMap()
{
Id(x => x.Id);
References(x => x.Student).ForeignKey("MyFKName");
}

what you are probably looking for is
public CourseMap()
{
Id(x => x.Id);
References(x => x.Student).KeyColumn("MyFKName");
}
ForeignKey is the name of the foreign key constraint

Related

Fluent NHibernate error: Must have same number of columns as the referenced primary key

I am new with Fluent NHibernate and I have a problem with a particular HasMany relationship.
I have three objects: User, Company and CompanyAddress
User references Company correctly and Company would reference CompanyAddress (but this fails).
Company mapping is composed like following:
public class CompanyMap : ClassMap<Company>
{
public CompanyMap()
{
Schema("company");
Table("LIST");
this.CompositeId(x => x.key)
.KeyProperty(x => x.applicationId, "APPLICATION_ID")
.KeyProperty(x => x.id, "ID")
.KeyProperty(x => x.userId, "USER_ID");
this.Map(x => x.vat, "VAT");
this.HasMany(x => x.addresses)
.Not.LazyLoad()
.Cascade.None();
this.References(x => x.user)
.Class<User>()
.Columns("APPLICATION_ID", "USER_ID")
.Insert()
.Update()
.Fetch.Select()
.Not.LazyLoad()
.Cascade.None();
}
}
and CompanyAddress is:
public class CompanyAddressMap : ClassMap<CompanyAddress>
{
public CompanyAddressMap()
{
Schema("[address]");
Table("COMPANY_LIST");
this.CompositeId(x => x.key)
.KeyProperty(x => x.applicationId, "APPLICATION_ID")
.KeyProperty(x => x.id, "ID")
.KeyProperty(x => x.entityId, "COMPANY_ID");
this.Map(x => x.country, "COUNTRY");
this.Map(x => x.province, "PROVINCE");
this.Map(x => x.region, "REGION");
this.Map(x => x.city, "CITY");
this.Map(x => x.address, "[ADDRESS]");
this.Map(x => x.description, "DESCRIPTION");
this.References(x => x.company)
.Class<Company>()
.Columns("APPLICATION_ID", "COMPANY_ID")
.Insert()
.Update()
.Fetch.Select()
.Not.LazyLoad()
.Cascade.None();
}
}
but I receive this error:
Foreign key (FK8DE1BC098F20893F:COMPANY_LIST [APPLICATION_ID, COMPANY_ID])) must have same number of columns as the referenced primary key (LIST [APPLICATION_ID, ID, USER_ID])
I need to reference AddressCompany with non primary key because Company is already referenced by User and so my question is:
How can I reference this foreign key using Fluent NHibernate without modifying the real foreign key defined into the database?
[EDIT]
i need to reference AddressCompany with non the primary key 'cause Company is already referenced by User and so my question is: how can i reference this foreign key using fluent nhibernate without modifying the real foreign key defined into the database?
i don't want to add USER_ID field to the [address].[COMPANY_LIST] table and i don't want to add userId field to AddressCompany class... 'cause is a useless field... the relationships are:
user.LIST
applicationId (pk)
id (pk)
company.LIST
applicationId (pk) (fk -> user.LIST(applicationId))
id (pk)
userId (pk) (fk -> user.LIST(id))
address.COMPANY_LIST
applicationId (pk) (fk -> company.LIST(applicationId))
id (pk)
companyId (pk) (fk -> company.LIST(id))
why nhibernate wants force me to reference only the exact primary key?
could i reference a subset of the primary key of Company class?
thanks so much...
The error seems pretty self evident from your mapping and error message
Foreign key (FK8DE1BC098F20893F:COMPANY_LIST [APPLICATION_ID,
COMPANY_ID])) must have same number of columns as the referenced
primary key (LIST [APPLICATION_ID, ID, USER_ID])
You mappings for CompanyMap maps your primary key for as three columns
this.CompositeId(x => x.key)
.KeyProperty(x => x.applicationId, "APPLICATION_ID")
.KeyProperty(x => x.id, "ID")
.KeyProperty(x => x.userId, "USER_ID");
but your references to Company in CompanyAddressMap only maps back to Company with 2 columns
this.References(x => x.company)
.Class<Company>()
.Columns("APPLICATION_ID", "COMPANY_ID")
.Insert()
.Update()
.Fetch.Select()
.Not.LazyLoad()
.Cascade.None();
Add the ID column to your columns listing.

Sharing field as composite key and foreign key in Fluent NHibernate

Consider following mapping code please :
public sealed class BankMapping : ClassMap<Bank>
{
public BankMapping()
{
CompositeId()
.KeyProperty(x => x.SerialNumber, "SerialBankRef")
.KeyProperty(x => x.FinancialPeriodId, "FinancialPeriodRef");
Map(x => x.Code);
Map(x => x.Title);
Map(x => x.Comment);
Map(x => x.IsActive);
HasMany(x => x.BankBranchs).KeyColumns.Add(new[] { "SerialBankRef", "FinancialPeriodRef" });
}
}
And the BankBranch mapping code is :
public sealed class BankBranchMapping : ClassMap<BankBranch>
{
public BankBranchMapping()
{
CompositeId()
.KeyProperty(x => x.FinancialPeriodId, "FinancialPeriodRef")
.KeyProperty(x => x.SerialNumber, "SerialNumber");
Map(x => x.Code);
Map(x => x.Title);
Map(x => x.Comment);
Map(x => x.IsActive);
Map(x => x.Address);
Map(x => x.Fax);
Map(x => x.Telephone);
References(x => x.Bank).Columns(new[] { "SerialBankRef", "FinancialPeriodRef" });
}
}
As you can see the FinancialPeriodRef field acts as foreign key and part of composite key in the BankBranch mapping and NHibernate builds DB correctly and everything seems to be fine until I try to insert a record in the BankBranch table.
The error System.IndexOutOfRangeException : Invalid index 10 for this SqlParameterCollection with Count=10. which indicates I've mapped a field (FinancialPeriodRef) twice as FK and PK appears and I have no idea how to fix the problem.
I need FinancialPeriodRef in the BankBranch as part of primary key while it's absolutely equal to FinancialPeriodRef from Bank.
I need this field to establish unique constraint and also benefits of composite key is essential.
You need to use KeyReference rather than KeyProperty to describe composite foreign keys.
public BankBranchMapping()
{
CompositeId()
.KeyReference(x => x.FinancialPeriodId, "FinancialPeriodRef")
.KeyReference(x => x.SerialNumber, "SerialNumber");
...
}
I had the exact same problem as you and after an hour or so came across this post: https://stackoverflow.com/a/7997225/569662 which pointed me right.

Fluent nhibernate : Problems when deleting a HasOne relationship

I have two classes
public PartMap()
{
Id(x => x.ID).GeneratedBy.Guid();
HasOne(x => x.Stock)
.Cascade.All();
}
public Stock
{
Id(x => x.ID).GeneratedBy.Guid();
References(x => x.Part);
}
Part has only one stock, that's the reason i used HasOne.
The data is inserted ok, I have a part , a stock and they are saved ok.
My problem is when trying to delete I get an error that the stock foreing key to part was violated
"ORA-02292: integrity constraint (PRINERGY.FK121AD9E59966BE23) violated " .
I see the it tries to delete the part without deleting the related stock before.
How can I solve it?
It seems like a one-to-one bidirectional association. There are two ways how to map this association in NH (and FNH): primary key association and foreign key association. Your example is closer to foreign key association.
Foreign key association
public PartMap()
{
Id(x => x.Id).GeneratedBy.Guid();
References(x => x.Stock).Unique().Cascade.All();
Map(x => x.Name);
}
public StockMap()
{
Id(x => x.Id).GeneratedBy.Guid();
HasOne(x => x.Part).Cascade.All().PropertyRef("Stock");
Map(x => x.Name);
}
Primary key association
public PartMap()
{
Id(x => x.Id).GeneratedBy.Guid();
HasOne(x => x.Stock).Cascade.All();
Map(x => x.Name);
}
public StockMap()
{
Id(x => x.Id).GeneratedBy.Foreign("Part");
HasOne(x => x.Part).Constrained();
Map(x => x.Name);
}
For more details see http://fabiomaulo.blogspot.com/2010/03/conform-mapping-one-to-one.html.

Fluent-Nhibernate References and PropertyRef Doing a Select With Lazy Load

I am using PropertyRef for one of my References properties. With LazyLoad() it still does a Select and loads the User entity, even though I never "hit" the SalesPerson property.
Order Mapping
Id(x => x.Id).GeneratedBy.Native();
References(x => x.SalesPerson)
.LazyLoad()
.PropertyRef(x => x.Username)
.Column("rsm");
Map(x => x.Title);
Order Class
public class Order : BaseEntity
{
...
public virtual User SalesPerson { get; set; }
public virtual string Title { get; set; }
...
}
User Mapping
Id(x => x.Id).GeneratedBy.Native();
Map(x => x.Username).Column("login");
User Class
public class User : BaseEntity
{
public virtual string Username { get; set; }
...
}
Generated Order Mapping
<many-to-one class="Project.User" lazy="proxy" name="SalesPerson" property-ref="Username">
<column name="rsm" />
</many-to-one>
Executing Code
var order = session.Get<Order>(1);
Console.WriteLine(order.Title);
Is there anyway to prevent the Select to load the User entity when I'm not using the User entity?
Has to do with property-ref see
NHibernate creates proxy via session.Load(), but not via Linq or Criteria API
And not that you asked, but also consider that many-to-one with proxy does not allow you to do type-checking if you subclass User, see
http://ayende.com/Blog/archive/2010/01/28/nhibernate-new-feature-no-proxy-associations.aspx
I don't think this is a bug in NHibernate. It depends on your mapping.
First, remember that the reference map will join the key (primary key and foreign key) between 2 mapping tables. To prevent SELECT + 1, just ignore the key joint.
References(x => x.SalesPerson)
.LazyLoad()
.PropertyRef(x => x.Username)
WithForeignKeyName("none") //disable key join.

Fluent Nhibernate composed entity, specify foreign key

I have a Fluent Nhibernate map like :
public class UserMap : ClassMap<PortalUser>
{
public UserMap()
{
WithTable("aspnet_Users");
Id(x => x.Id, "UserId")
.GeneratedBy.Guid();
Map(x => x.Name, "UserName");
Map(x => x.Login, "LoweredUserName");
WithTable("LdapUsers", m => m.Map(x => x.FullName, "FullName"));
}
}
My foreign key column in table "LdapUser" is UserId but the select that gets generated is going to look for a "PortalUserId".
Is there a way to specify the relation key direcly?
Try this:
...
WithTable("LdapUsers", m => {
m.Map(x => x.FullName, "FullName");
m.WithKeyColumn("UserId");
});