I have the following tables and entities which need to be mapped in Fluent NHibernate.
Tables:
CREATE TABLE workarea
(
id uuid NOT NULL,
name character varying(255) NOT NULL,
CONSTRAINT pk_workarea PRIMARY KEY (id),
)
CREATE TABLE element
(
id uuid NOT NULL,
name character varying(255) NOT NULL,
CONSTRAINT pk_element PRIMARY KEY (id),
)
CREATE TABLE attachment
(
id uuid NOT NULL,
filename character varying(255) NOT NULL,
CONSTRAINT pk_attachment PRIMARY KEY (id),
)
CREATE TABLE objectattachment
(
id uuid NOT NULL,
attachmentid uuid NOT NULL,
attachmenttype string NOT NULL,
objectid uuid NOT NULL,
CONSTRAINT pk_objectattachment PRIMARY KEY (id),
CONSTRAINT fk_oa_a FOREIGN KEY (attachmentid)
REFERENCES attachment (id) MATCH SIMPLE
ON UPDATE RESTRICT ON DELETE RESTRICT,
CONSTRAINT fk_oa_at FOREIGN KEY (attachmenttypeid)
REFERENCES attachmenttype (id) MATCH SIMPLE
ON UPDATE RESTRICT ON DELETE RESTRICT
)
The idea under this database design is as follows:
A "workarea" or an "element" could have several "attachment" files and an "attachment" file could be referred to by several "workarea"s or "element"s.
A "workarea" or an "element" could refer to the same "attachment" file.
So the relations between "attachment"s and "workarea"s or "element"s are stored in "objectattachment " table, in which:
"attachmentid" field refers to the identifier of a specific "attachment"s.
"attachmenttype" field (discriminator) defines whether this relation is between "attachment"s and "workarea"s or between "attachment"s and "element"s.
"objectid" field refers to the identifier of a specific "workarea"s or "element"s, depending on the value of the above "attachmenttype" field.
Based on the database design, I then define domain model classes as follows:
public class WorkArea
{
private Guid _id = Guid.Empty;
private string _name;
public virtual Guid Id
{
get { return _id ; }
set { _id = value; }
}
public virtual string Name
{
get { return _name ; }
set { _name = value; }
}
}
public class Element
{
private Guid _id = Guid.Empty;
private string _name;
public virtual Guid Id
{
get { return _id ; }
set { _id = value; }
}
public virtual string Name
{
get { return _name ; }
set { _name = value; }
}
}
public class Attachment
{
private Guid _id = Guid.Empty;
private string _fileName;
public virtual Guid Id
{
get { return _id ; }
set { _id = value; }
}
public virtual string FileName
{
get { return _fileName; }
set { _fileName= value; }
}
}
public class WorkAreaAttachment : Attachment
{
private WorkArea _workArea;
public virtual WorkArea WorkArea
{
get { return _workArea; }
set { _workArea = value; }
}
}
public class ElementAttachment : Attachment
{
private Element _element;
public virtual Element Element
{
get { return _element; }
set { _element = value; }
}
}
Now my question is whether I could mapping these domain model classes with the above database design. If yes, then how could I do that? If no, then how do I change the domain model classes to support Fluent NHibernate mapping against the designed database as I don't want to change the current database design (i.e. create separate "attachment" tables for "workarea" and "element").
Regards, Quan
public class AttachmentLink
{
private Attachment _attachment;
public virtual Attachment Parent
{
get { return _attachment; }
set { _attachment = value; }
}
private IHasAttachments _linkedTo;
public virtual IHasAttachments LinkedTo
{
get { return _linkedTo; }
set { _linkedTo = value; }
}
}
// in AttachmentMap
HasMany(x => x.Links)
.Table("objectattachment");
// map the component
sealed class AttachmentLinkMap : ComponentMap<AttachmentLink>
{
public AttachmentLinkMap()
{
References(x => x.Attachment, "attachmentid");
ReferencesAny(x => x.LinkedTo)
.IdentityType<Guid>()
.EntityIdentifierColumn("objectid")
.EntityTypeColumn("attachmenttype")
.AddMetaValue<WorkArea>(typeof(WorkArea).Name.ToLower())
.AddMetaValue<Element>(typeof(Element).Name.ToLower())
.Not.LazyLoad(); // to prevent false proxies
}
}
// in ElementMap, and almost the same in WorkAreaMap
HasManyToMany(x => x.Attachments)
.Where("attachmenttype='element'")
Note: you don't need an Id column in the link table