This question is really to establish if what im trying to achieve is possible.
I have three tables i'll omit the actual names to keep it simple and less confusing
so we have
Person [
PID - uniqueidentifier PK
]
Applicant
[
PID - uniqueidentifier PK,
AID - varchar(20)]
Student
[
PID - uniqueidentifier PK,
SID - int]
both the student and applicant tables are related to the person table with a one-to-one relationship (where the primary key is held in the person table), but are not related to each other.
I have the following domain objects
public class Person
{
public virtual Guid PID{get;set;}
}
public class Applicant: Person
{
public virtual string AID {get;set;}
}
public class Student:Person
{
public virtual int SID {get;set;}
}
These each have a map class derived from either ClassMap or SubClassMap
public class PersonMap: ClassMap<Person>
{
public PersonMap()
{
Id(x => x.PID).GeneratedBy.Assigned();
Table("Person");
}
}
public class ApplicantMap: SubclassMap<Applicant>
{
public ApplicantMap()
{
Table("Applicant");
KeyColumn("PID");
Map(x => x.AID);
}
}
public class StudentMap:SubclassMap<Student>
{
public StudentMap()
{
Table("Student");
KeyColumn("PID");
Map(x => x.SID);
}
}
My question is, is it possible to have a person who is an applicant and a student at the same time.In database terms I can have a row in each table that holds the same PID, will nhibernate allow me to save and retrieve all three objects?
one of the problems I have is trying to insert into student when the id already exists for an applicant and of course person..
public void MakePersonAStudent(Person p)
{
Student newStudent = new Student();
newStudent.PID = p.PID;
newStudent.SID = getNewStudentID();
Session.Save(newPerson);
}
The exception generated is:
a different object with the same identifier value was already associated with the session .... 73e5fd90-c27a-49d8-87dc-cd6413c120a2, of entity: Student
use single_table inheritance. doc for hibernate: http://docs.jboss.org/hibernate/core/3.3/reference/en/html/inheritance.html
Related
I am a beginner at using Fluent NHibernate.
I am developing a C# application that has to interact with an existing database.Let say I have 2 tables: Items and ItemsList.
Items: ID INT ItemName VARCHAR(100)
ItemsList: ID INT ChildItemID INT
I've built 2 classes and their mapping:
public class Items
{
public virtual int id {get; set;}
public virtual string itemName {get; set;}
}
public class ItemsMap : ClassMap<Items>
{
public ItemsMap()
{
Id(x => x.id).GeneratedBy.Increment();
Map(x => x.itemsName);
}
}
public class ItemsList()
{
public virtual int id {get; set;}
public virtual IList<Items> childItems {get; set;}
public ItemsList()
{
childItems = new List<Items>();
}
}
public class ItemsListMap : ClassMap<ItemsList>
{
public ItemsListMap()
{
Id(x => x.id).GeneratedBy.Increment();
HasMany(x => x.childItems).KeyColumn("childID").Cascade.All();
}
}
And finally, I insert an item in the itemsList and save it all:
try
{
using( ISession session = NH.OpenSession())
{
using(ITransaction transaction = session.BeginTransaction())
{
Items i = New Items()
i = session.get<Items>(1);
ItemsList il = new ItemsList();
il.childID.Add(i);
session.SaveOrUpdate(il);
transaction.Commit();
}
}
}
So when I commit, I have a new entry in ItemsList table, but the childID is blank.
Question:
All the examples I see has a reference to ItemsListID in Items table. But I don't want to have this reference since I want the item to be unique in the items table. How can I acheve that?
The NHibernate native way for expressing the unique reference, is:
5.1.12. one-to-one
There are two varieties of one-to-one association:
primary key associations
unique foreign key associations
Primary key associations don't need an extra table column; if two rows are related by the association then the two table rows share the same primary key value. So if you want two objects to be related by a primary key association, you must make sure that they are assigned the same identifier value!...
Other words, Tables would look like this (Table Items generates the value of ItemID, table ItemsList takes that value and stores it in the ItemID ) :
Items: ItemID INT ItemName VARCHAR(100)
ItemsList: ItemID INT
The C# would be (I changed Items into Item and ItemList into ItemMoreDetails, because it is not a list anymore)
public class Item
{
public virtual int ItemId { get; set; }
...
public virtual ItemMoreDetails ItemMoreDetails {get; set; }
public class ItemMoreDetails
{
public virtual int ItemId { get; set; }
...
public virtual Item Item {get; set;}
The mapping would be (in fluent):
// Parent side
public class ItemMap : ClassMap<Item>
{
public ItemMap()
{
Id(x => x.id).GeneratedBy.Increment();
...
HasOne(x => x.ItemMoreDetails).Cascade.All();
// child side
public class ItemMoreDetailsMap: ClassMap<ItemMoreDetails>
{
public ItemMoreDetailsMap()
{
...
References(x => x.parent).Unique();
See the doc:
HasOne / one-to-one
I have a problem with mapping in NHibernate.
The Order table has the Invoice_Id column which is the nullable FK to the Invoice table.
The problem is, when I load an Invoice which Id exists in the Order table, I see that ConnectedOrder property is null, why?
public class Invoice
{
public virtual Order ConnectedOrder { get; set; }
}
public class Order
{
public virtual Invoice ConnectedInvoice { get; set; }
}
public class InvoiceMap : ClassMap<Invoice>
{
public InvoiceMap()
{
this.References(x => x.ConnectedOrder).Nullable();
}
}
public class OrderMap : ClassMap<Order>
{
public OrderMap()
{
this.References(x => x.ConnectedInvoice).Nullable();
}
}
edit
I've changed my classes and mappings like Radim Köhler said, then I found that topic
Fluent NHibernate One-To-Many Mapping
and there was the need to also add:
this.HasMany(x => x.Orders)
.KeyColumn("Invoice_id")
.Inverse()
.Cascade
.AllDeleteOrphan();
and now it works
You may not like it, but the table structure described above, is not representing Entity relations you've created (so called one-to-one).
In case, that one table contains column referencing the another table (FK), we have scenario:
Each Order has exactly one (or null) Invoice. (many-to-one)
Invoice can be referenced by none or one or many Orders. (one-to-many)
That means, that we should express Entities like this:
public class Invoice
{ // many orders could reference us
public virtual IList<Order> Orders { get; set; }
...
public class Order
{ // unchanged
public virtual Invoice ConnectedInvoice { get; set; }
...
And the mapping should be:
public InvoiceMap()
{ // HasMany is one-to-many
this.HasMany(x => x.Orders)
...
}
public OrderMap()
{ // References is many-to-one
this.References(x => x.ConnectedInvoice).Nullable();
...
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.
We have a multi-tenant database - i.e. common database used by multiple clients, hence each table will have a "ClientID" column indicating the Tenant.
We are using Fluent NHibernate for ORM and looking for the best approach to tackle multi-tenancy: each Mapping class needs to map ClientID, however, the value would come from the User Account object - i.e. from User Session of some sort.
Is there a nice and easy way to achieve this using Fluent NHibernate? If so, could you provide an example?
I'm not entirely sure if this is what your asking but if you need each class to map to the ClientId, here's one example.
Basically, each class would have a UserAccount property or whatever class is going to store the user's account information that has the ClientId property on it. Then in your Fluent NHibernate mapping, you can map the classes together using the References() method. See example below:
public class UserAccount
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual IList<Bill> Bills { get; set; }
}
public class Bill
{
public virtual int BillId { get; set; }
public virtual UserAccount User { get; set; }
}
public class UserAccount : ClassMap<UserAccount>
{
public UserAccount()
{
Id( x => x.Id ).Column( "ClientId" );
Map( x => x.Name );
HasMany( x => x.Bills );
}
}
public class BillMap : ClassMap<Bill>
{
public BillMap()
{
Id( x => x.Id ).Column( "BillId" );
References( x => x.User ).Column( "ClientId" );
}
}
So in your Bill table, you would have a ClientId column which in database terms is really a foreign key referencing the UserAccount table's primary key column which would also be named ClientId.
If you are truly going to have a large amount of tables that are all going to have a ClientId column, you also have the option of abstracting that out to a base class that your entities inherit from that would already have the UserAccount property on it. You could do the same base class approach for your Fluent NHibernate mapping files as well.
I'm trying to map the following tables/entities in FNH and seem to be getting nowhere fast!
**Tables**
Contacts
ID (PK - int - generated)
...
PhoneTypes
ID (PK - varchar - assigned) (e.g. MOBILE, FAX)
ContactPhones
ContactRefId (PK - FK to Contacts)
PhoneTypeRefId (PK - FK to PhoneTypes)
...
(I should note that I am also using the S#arp Architecture framework)
**Entities**
public class Contact : Entity
{
(The ID property is defined in the Entity base class and is type int)
public virtual ICollection<ContactPhone> PhoneNumbers { get; set; }
}
public class PhoneType : EntityWithTypedId<string>, IHasAssignedId<string>
{
(The ID property is defined in the base class and is type string)
....
}
public class ContactPhone : EntityWithTypedId<ContactPhoneId>, IHasAssignedId<ContactPhoneId>
{
public virtual Contact Contact { get; set; }
public virtual PhoneType PhoneType { get; set; }
....
}
I read that it is advisable when working with composite ids, to separate the composite id into a different class.
hibernate composite key
public class ContactPhoneId : EntityWithTypedId<ContactPhoneId>, IHasAssignedId<ContactPhoneId>
{
public virtual Contact Contact { get; set; }
public virtual PhoneType PhoneType { get; set; }
}
...I could just make this class serializable and override
Equals and GetHashCode myself instead of using the S#arp Arch base class.
I've tried so many combinations of mappings that I'm now completely confused.
This is my latest shot:
public class ContactMap : IAutoMappingOverride<Contact>
{
public void Override(AutoMapping<Contact> mapping)
{
mapping.HasMany<ContactPhone>(x => x.PhoneNumbers)
.KeyColumns.Add("ContactRefId")
.KeyColumns.Add("PhoneTypeRefId")
.AsSet()
.Inverse()
.Cascade.All();
}
}
public class PhoneTypeMap : IAutoMappingOverride<PhoneType>
{
public void Override(AutoMapping<PhoneType> mapping)
{
mapping.Id(x => x.Id).Column("Id").GeneratedBy.Assigned();
}
}
public class ContactPhoneMap : IAutoMappingOverride<ContactPhone>
{
public void Override(AutoMapping<ContactPhone> mapping)
{
mapping.Table("ContactPhones");
mapping.CompositeId<ContactPhoneId>(x => x.Id)
.KeyReference(y => y.Contact, "ContactRefId")
.KeyReference(y => y.PhoneType, "PhoneTypeRefId");
}
}
I've had many exceptions thrown when trying to generate the mappings, the latest of which is:
Foreign key (FK672D91AE7F050F12:ContactPhones [ContactRefId, PhoneTypeRefId]))
must have same number of columns as the referenced primary key (Contacts [Id])
Does anyone see anything obvious that I'm doing wrong? I'm new to NH and FNH, which may be obvious from this post. :-) Also, has anyone used Composite Ids like this while using S#arp Architecture? What are the best practices (other than to use surrogate keys :-) ) ?
Many thanks...and sorry about the long post.
I have a many to many relationship too. I've got mine setup like this:
mapping.HasManyToMany(x => x.Artists).Cascade.All().Inverse().Table("ArtistImages");
The ArtistImages table has primary keys for tables Artists and Images.