I am using fluent nHibernate for my mappings as follow:
public class ContentTagMap: ClassMap<Employee>
{
public EmployeeMap()
{
Id(t => t.Id);
Map(t => t.Name);
HasManyToMany(t => t.Company);
}
}
public class CompanyMap: ClassMap<Company>
{
public HelpMap()
{
Id(h => h.Id);
Map(h => h.CompanyName).Length(6000);
Map(h => h.address).Length(6000);
HasManyToMany(h => h.Employee);
}
}
These mappings produce Employee Table ,Company Table and EmployeeToCompany Table
Employee Table
Id Name
1 John
2 MAX
Company Table
Id CompanyName address
1 HTC ABC
2 HTC2 India
EmployeeToCompany Table
Employee_Id Company_Id
1 1
2 1
How can I delete the employee with Id 1?
Unless I'm misunderstanding your question you should be asking:
How can i delete the content of the table using NHibernate?
Fluent NHibernate is only a tool to aid in the mapping of your entities. NHibernate is what you use to create, read, update and delete data. In any event:
9.5. Deleting persistent objects
ISession.Delete() will remove an object's state from the database. Of
course, your application might still hold a reference to it. So it's
best to think of Delete() as making a persistent instance transient.
From the NHibernate Documentation
You probably want to also define a Cascading style on your many to many relationship (HasManyToMany) in your mapping.
If you use Cascade.SaveUpdate in your many to many whenever you delete an entity on one side of the relationship it will delete that entity and any relationships. If you remove the association (ex. if you removed an Employee from a Company) it will only delete the relationship (EmployeeToCompany). This is what I've typically found to work in the case of many to many relationships.
Look at this article for more details on mapping and using a many to many relationship in Fluent NHibernate.
how to keep many to many relationships in sync with nhibernate?
Related
I am using FluentNHibernate and have two classes that have a 1:1 relationship. ItemA includes
public virtual ItemB { get; set; }
and mapped with
HasOne(x => x.ItemB).ForeignKey("ItemID");
I am only interested in ItemA, but because it has the following map I'm seeing two database calls when I run:
var res = session.Query<ItemA>()
.SingleOrDefault(x => x.ItemId.ToString() =="AC3E30FF-E767-440F-AB1F-0000293C5A0C");
I get a select for ItemA table and a select for ItemB table.
If I then make a change back to References, I get only one:
References(x => x.ItemB).ForeignKey("ItemId");
This is perhaps trivial, but I have another class which has been given a number of "HasOne" relationships for tables I do not need to be using and yet Select queries are becoming rather complex.
I tried adding "Lazyload" to the mapping, but that didn't seem to change anything. Is there any way of keeping the HasOne relationship but being able to generate a simple, single "select" query for my "Query" (i.e. Select [columns] from ItemA where ItemID =...)?
No, there is no way how to achieve that. One-to-one will simply be eager, no lazy setting will help.
But as stated here: 5.1.11. one-to-one
A one-to-one association ...
... Alternatively, a foreign key with a unique constraint, from Employee to Person, may be expressed as:
<many-to-one name="Person" class="Person" column="PERSON_ID" unique="true"/>`
// which is in fluent References()
And this association may be made bidirectional by adding the following to the Person mapping:
<one-to-one name="Employee" class="Employee" property-ref="Person"/>
So, I would suggest go with References mapping
References(x => x.ItemB).Unique().Cascade.All();
See: How to do a fluent nhibernate one to one mapping?
I have a [User] table/class and a [Company] table/class and there is a link-table [UserCompany] between them.
When editing a User, beside basic information people also could change that user's access Companies, so I do the map like this in UserMap.cs:
HasManyToMany(u => u
.Companies)
.Cascade.SaveUpdate()
.Table("UserCompany")
.ParentKeyColumn("UserId")
.ChildKeyColumn("CompanyCode")
.Not.LazyLoad();
Also in CompanyMap.cs I set inverse like this:
HasManyToMany(c => c.Users)
.Inverse()
.Table("UserCompany")
.ParentKeyColumn("CompanyCode")
.ChildKeyColumn("UserId");
The problem now is: I could update [User] information/table, plus the linking data in [UserCompany] table. However, the Fluent Nhibernate also update the [Company] table which I don't need at all.
Is there any way I could let FN not update Company table?
To stop cascading updates just remove the
.Cascade.SaveUpdate()
from your Many-to-many mapping.
It could be a bit confusing. In comparison with the cascading used on <list>s and <map>s. In that case, the update is done directly on the child table (parent has more children... child contains the ParentId - cascade is reasonable to do operation on the child record)
But here we are working with a pair table. The relation is stored there. And this table will be always managed by NHibernate (implicit cascading).
The setting .Cascade.SaveUpdate() goes to other end of the many-to-many relation. To company table in our case. It could be handy.. but you can omit that and get everything running as expected.
I have to an existing schema and I want to map it with nhibernate.
entities / table schema:
post {
pk_id
prod_id
prod_internid
title
}
tag {
pk_t_id
prod_id
prod_internid
name
}
A post can have multiple tags and there is a foreign key contraint from the tag to the post table with the two columns prod_id and prod_internid.
I've tried this:
PostMap {
// tags is a list
HasMany(x => x.tags).KeyColumns.Add("prod_id", "prod_internid");
}
TagMap {
References(x => x.post).Columns("prod_id", "prod_internid");//.ForeignKey();
}
I get this error:
NHibernate.FKUnmatchingColumnsException: Foreign key (FK98806C8630C05A78:tag [prod_id, prod_internid])) must have same number of columns as the referenced primary key (post [pk_id])
How can I map it the right way?
I don't think this functionality is currently supported in NHibernate but it is in Hibernate. Seems like you or someone would need to port it over. Take a look at this NH Issue:
https://nhibernate.jira.com/browse/NH-1722
I also found this previous StackOverflow article regarding this:
many-to-one with multiple columns
I've got a many-to-many association between Lists and ListItems: a List knows about its Items, but a ListItem doesn't know about the containing lists. The cascade is saveupdate.
So, whenever I'm trying to delete a ListItem entity, I'm getting an SQLException saying I'm breaking the referential integrity. NHibernate tries to delete my ListItem without deleting the corresponding row in the linking table. The question is, is it possible to instruct NHibernate to delete my ListItem without breaking the referential integrity?
In case I have to manually remove the item from all containing lists, how do I properly do that?
Thanks a lot for any advice.
ulu
You need to set the mapping on the child to inverse=true. From another thread:
When you call SaveOrUpdate NHibernate
first deletes all of the child
objects. Then, because neither
relationship is marked as inverse,
NHibernate also tries to set the
foreign key column in your child table
to null. Since the rows have already
been deleted, you receive the second
error. You need to set inverse=true on
one side of your relationship to fix
this. This is usually done on the one
(primary key or parent) side. If you
do not do this, NHibernate will make
the appropriate updates for each side
of the relationship.
public class StoreMap : ClassMap<Store>
{
public StoreMap()
{
Id(x => x.Id);
Map(x => x.Name);
HasMany(x => x.Staff)
.Inverse() // Magic code!
.Cascade.All();
}
}
I have these classes:
public class User
{
public IList<Order> LastOrders { get; set;}
}
public class Order {}
Where LastOrders is many-to-many map.
How do I tell (Fluent) NHibernate to remove Order from LastOrders collections for all users when I delete an Order? Is it possible?
That is (db save/load code skipped)
user.LastOrders.Add(order);
Session.Delete(order);
Assert(!user.LastOrders.Contains(order));
Currently I do it manually (lookup for users, update collection, save) before deletion. Without this, NHibernate can't delete Order because it is referenced by users' LastOrders.
You can safely delete the Order if the collection mapping is set to ignore missing rows.
This will leave orphaned rows in the collection table which will be ignored by NHibernate. These can be cleaned up in some batch process.
HasManyToMany(x => x.LastOrders)
.NotFound.Ignore();
This will give you faster deletes then your current approach. The disadvantage is that your collection tables will be inconsistent with your model for a time.