流利的nhibernate - 多对多关系的属性关系 [英] fluent nhibernate - Many to Many relationship with attribute on relationship
问题描述
我有我的代码工作,但我在表/ ddl中获得2个额外的列,以表示一个多对多的关系,~~但关系上的属性(标量)。 b
$ b
我使用
1.2.0.712(FluentNHibernate.dll)
3.1.0.4000(NHibernate.dll)
< h2>实体:
public partial class Employee
{
public Employee()
{
CommonConstructor();
private void CommonConstructor()
{
this.MyEmployeeToJobTitleMatchLinks = new List< EmployeeToJobTitleMatchLink>();
}
公共虚拟Guid? EmployeeUUID {get;组; }
公共虚拟字节[] TheVersionProperty {get;组; }
公共虚拟字符串SSN {get;组; }
public virtual string LastName {get;组; }
公共虚拟字符串名字{get;组; }
public virtual DateTime CreateDate {get;组; }
public virtual DateTime HireDate {get;组; }
公共虚拟ICollection< EmployeeToJobTitleMatchLink> MyEmployeeToJobTitleMatchLinks {get;组; }
public virtual void AddJobTitleLink(EmployeeToJobTitleMatchLink link)
{
link.TheEmployee = this;
if(!this.MyEmployeeToJobTitleMatchLinks.Contains(link))
{
this.MyEmployeeToJobTitleMatchLinks.Add(link);
}
如果
{
link.TheJobTitle.MyJobTitleToEmployeeMatchLinks.Add(链接)(link.TheJobTitle.MyJobTitleToEmployeeMatchLinks.Contains(链接)!);
$ b $ public virtual void RemoveJobTitleLink(EmployeeToJobTitleMatchLink link)
{
link.TheEmployee = this;
if(this.MyEmployeeToJobTitleMatchLinks.Contains(link))
{
this.MyEmployeeToJobTitleMatchLinks.Remove(link);
}
如果(link.TheJobTitle.MyJobTitleToEmployeeMatchLinks.Contains(链接))
{
link.TheJobTitle.MyJobTitleToEmployeeMatchLinks.Remove(联系);
$ b public partial class JobTitle
{
public JobTitle()
{
CommonConstructor();
private void CommonConstructor()
{
this.MyJobTitleToEmployeeMatchLinks = new List< EmployeeToJobTitleMatchLink>();
}
公共虚拟Guid? JobTitleUUID {get;组; }
公共虚拟字节[] TheVersionProperty {get;组; }
公共虚拟字符串JobTitleName {get;组; }
public virtual DateTime CreateDate {get;组; }
公共虚拟ICollection< EmployeeToJobTitleMatchLink> MyJobTitleToEmployeeMatchLinks {get;组; }
public virtual void AddEmployeeLink(EmployeeToJobTitleMatchLink link)
{
link.TheJobTitle = this;
if(!this.MyJobTitleToEmployeeMatchLinks.Contains(link))
{
this.MyJobTitleToEmployeeMatchLinks.Add(link);
}
如果
{
link.TheEmployee.MyEmployeeToJobTitleMatchLinks.Add(链接)(link.TheEmployee.MyEmployeeToJobTitleMatchLinks.Contains(链接)!);
}
$ b public virtual void RemoveEmployeeLink(EmployeeToJobTitleMatchLink link)
{
link.TheJobTitle = this;
if(this.MyJobTitleToEmployeeMatchLinks.Contains(link))
{
this.MyJobTitleToEmployeeMatchLinks.Remove(link);
}
如果(link.TheEmployee.MyEmployeeToJobTitleMatchLinks.Contains(链接))
{
link.TheEmployee.MyEmployeeToJobTitleMatchLinks.Remove(联系);
$ b公共部分类EmployeeToJobTitleMatchLink
$ b $ public EmployeeToJobTitleMatchLink()
{
//this.Id = Guid.NewGuid(); / *这与< generator class =assigned>< / generator> * /
}
公共虚拟Guid? LinkSurrogateUUID {get;组; }
$ b $ *这些是~~关系的标量属性~~ * /
public virtual int PriorityRank {get; set;}
public virtual DateTime JobStartedOnDate {get; set;}
public virtual Employee TheEmployee {get; set;}
public virtual JobTitle TheJobTitle {get; set;}
}
映射:
public class EmployeeMap:ClassMap< ; Employee>
{
public EmployeeMap()
{
Id(x => x.EmployeeUUID).GeneratedBy.GuidComb();
OptimisticLock.Version();
版本(x => x.TheVersionProperty)
.Column(MyVersionColumn)
.Not.Nullable()
.CustomSqlType(timestamp )
.Generated.Always();
Map(x => x.SSN);
Map(x => x.LastName);
Map(x => x.FirstName);
Map(x => x.CreateDate);
Map(x = GT; x.HireDate);
HasMany(x => x.MyEmployeeToJobTitleMatchLinks)
.Inverse()
.Cascade.All();
public class JobTitleMap:ClassMap< JobTitle>
{
public JobTitleMap()
{
Id(x => x.JobTitleUUID).GeneratedBy.GuidComb();
OptimisticLock.Version();
版本(x => x.TheVersionProperty)
.Column(MyVersionColumn)
.Not.Nullable()
.CustomSqlType(timestamp)
.Generated.Always();
Map(x => x.JobTitleName);
Map(x => x.CreateDate);
HasMany(x => x.MyJobTitleToEmployeeMatchLinks)
.Inverse()
.Cascade.All();
}
}
public class EmployeeToJobTitleMatchLinkMap:ClassMap< EmployeeToJobTitleMatchLink>
{
public EmployeeToJobTitleMatchLinkMap()
{
Id(x => x.LinkSurrogateUUID).GeneratedBy.GuidComb();
Map(x => x.PriorityRank);
Map(x => x.JobStartedOnDate);
引用(x => x.TheEmployee).Column(TheEmployeeUUID)。Not.Nullable(); / *与The错误的命名约定,但留在这里,因此可以很容易地在DDL * /
引用(x => x.TheJobTitle).Column(TheJobTitleUUID)。Not.Nullable(); / *与The错误的命名约定,但留在这里可以很容易地看到DDL * /
}
}
这工作正常, m在ddl中获得2个额外的(可空)列。它们在下面标有星号(*)。
选择*从[dbo]。[EmployeeToJobTitleMatchLink]
LinkSurrogateUUID
PriorityRank
JobStartedOnDate
TheEmployeeUUID
TheJobTitleUUID
* Employee_id
* JobTitle_id
我知道这是按惯例。 (名称上带有_id)。
但是我不需要这些列。我需要能够有自定义的名称。
(在这个模拟的例子中,TheEmployeeUUID和TheJobTitleUUID。)
我的游戏结束是:
SELECT * FROM [DBO]。[EmployeeToJobTitleMatchLink]
LinkSurrogateUUID(唯一标识符,SurrogateKey)结果,
PriorityRank(标量,INT)
JobStartedOnDate(标量,日期时间)
TheEmployeeUUID (唯一标识符,FK回dbo.Employee.EmployeeUUID)
TheJobTitleUUID(唯一标识符,FK回dbo.JobTitle.JobTitleUUID)
上的属性(一个或多个)这种关系是非常重要的。 (PriorityRank和JobStartedOnDate在这个模拟的例子。)
谢谢。
我〜如此接近
编辑:
工作映射:
public class EmployeeMap:ClassMap< Employee>
{
public EmployeeMap()
{
Id(x => x.EmployeeUUID).GeneratedBy.GuidComb();
OptimisticLock.Version();
版本(x => x.TheVersionProperty)
.Column(MyVersionColumn)
.Not.Nullable()
.CustomSqlType(timestamp)
.Generated.Always();
地图(x => x.SSN);
Map(x => x.LastName);
Map(x => x.FirstName);
Map(x => x.CreateDate);
Map(x => x.HireDate);
的hasMany(X => x.MyEmployeeToJobTitleMatchLinks)
.Inverse()
.Cascade.All()
.KeyColumn( TheEmployeeUUID)
;
公共类JobTitleMap:ClassMap< JobTitle>
{
public JobTitleMap()
{
Id(x => x.JobTitleUUID).GeneratedBy.GuidComb();
OptimisticLock.Version();
版本(x => x.TheVersionProperty)
.Column(MyVersionColumn)
.Not.Nullable()
.CustomSqlType(timestamp)
.Generated.Always();
Map(x => x.JobTitleName);
Map(x => x.CreateDate);
的hasMany(X => x.MyJobTitleToEmployeeMatchLinks)
.Inverse()
.Cascade.All()
.KeyColumn( TheJobTitleUUID)
;
public class EmployeeToJobTitleMatchLinkMap:ClassMap< EmployeeToJobTitleMatchLink>
{
public EmployeeToJobTitleMatchLinkMap()
{
Id(x => x.LinkSurrogateUUID).GeneratedBy.GuidComb();
Map(x => x.PriorityRank);
Map(x => x.JobStartedOnDate);
引用(x => x.TheEmployee).Column(TheEmployeeUUID)。Not.Nullable(); / *与The错误的命名约定,但留在这里可以看到很容易在DDL * /
引用(x => x.TheJobTitle).Column(TheJobTitleUUID)。Not.Nullable(); / *错误的命名约定与The,但留在这里,所以它可以在DDL中很容易看到* /
}
}
感谢弥敦道!
b
我学到的一个新术语是Google / binging自己是
物化关系
这是在这个页面的评论区:
LINK1
那么这个页面会在将来死掉的时候,这里就是粘贴的评论:
它被称为物化关系(ref: http://www.orm.ne在NIAM / ORM中,它通常被定义为一个关系,它本身就是一个具有属性的实体。客体关系总是形成至少一个m:n的关系。
(来自 http://weblogs.asp.net/fbouma/ )
我想你需要添加一个KeyColumn(key-name)作为HasMany映射的一部分, JobTitleMap和EmplyeeMap。这是因为fluent-nhibernate正在使用约定在EmployeeToJobTitleMatchLink表中创建FK。使用KeyColumn作为HasMay映射的一部分应该覆盖约定。
类似于以下内容: -
public class JobTitleMap:ClassMap< JobTitle>
{
public JobTitleMap()
{
Id(x => x.JobTitleUUID).GeneratedBy.GuidComb();
OptimisticLock.Version();
版本(x => x.TheVersionProperty)
.Column(MyVersionColumn)
.Not.Nullable()
.CustomSqlType(timestamp)
.Generated.Always();
Map(x => x.JobTitleName);
Map(x => x.CreateDate);
HasMany(x => x.MyJobTitleToEmployeeMatchLinks)
.Inverse()
.Cascade.All()
**。KeyColumn(TheJobTitleUUID)**
}
}
I have my code working, but I'm getting 2 extra columns in the table/ddl, to represent a Many to Many relationship, ~~but~~ with attributes (scalars) on the relationship.
I am using 1.2.0.712 (FluentNHibernate.dll) 3.1.0.4000 (NHibernate.dll)
Entities:
public partial class Employee
{
public Employee()
{
CommonConstructor();
}
private void CommonConstructor()
{
this.MyEmployeeToJobTitleMatchLinks = new List<EmployeeToJobTitleMatchLink>();
}
public virtual Guid? EmployeeUUID { get; set; }
public virtual byte[] TheVersionProperty { get; set; }
public virtual string SSN { get; set; }
public virtual string LastName { get; set; }
public virtual string FirstName { get; set; }
public virtual DateTime CreateDate { get; set; }
public virtual DateTime HireDate { get; set; }
public virtual ICollection<EmployeeToJobTitleMatchLink> MyEmployeeToJobTitleMatchLinks { get; set; }
public virtual void AddJobTitleLink(EmployeeToJobTitleMatchLink link)
{
link.TheEmployee = this;
if (!this.MyEmployeeToJobTitleMatchLinks.Contains(link))
{
this.MyEmployeeToJobTitleMatchLinks.Add(link);
}
if (!link.TheJobTitle.MyJobTitleToEmployeeMatchLinks.Contains(link))
{
link.TheJobTitle.MyJobTitleToEmployeeMatchLinks.Add(link);
}
}
public virtual void RemoveJobTitleLink(EmployeeToJobTitleMatchLink link)
{
link.TheEmployee = this;
if (this.MyEmployeeToJobTitleMatchLinks.Contains(link))
{
this.MyEmployeeToJobTitleMatchLinks.Remove(link);
}
if (link.TheJobTitle.MyJobTitleToEmployeeMatchLinks.Contains(link))
{
link.TheJobTitle.MyJobTitleToEmployeeMatchLinks.Remove(link);
}
}
}
public partial class JobTitle
{
public JobTitle()
{
CommonConstructor();
}
private void CommonConstructor()
{
this.MyJobTitleToEmployeeMatchLinks = new List<EmployeeToJobTitleMatchLink>();
}
public virtual Guid? JobTitleUUID { get; set; }
public virtual byte[] TheVersionProperty { get; set; }
public virtual string JobTitleName { get; set; }
public virtual DateTime CreateDate { get; set; }
public virtual ICollection<EmployeeToJobTitleMatchLink> MyJobTitleToEmployeeMatchLinks { get; set; }
public virtual void AddEmployeeLink(EmployeeToJobTitleMatchLink link)
{
link.TheJobTitle = this;
if (!this.MyJobTitleToEmployeeMatchLinks.Contains(link))
{
this.MyJobTitleToEmployeeMatchLinks.Add(link);
}
if (!link.TheEmployee.MyEmployeeToJobTitleMatchLinks.Contains(link))
{
link.TheEmployee.MyEmployeeToJobTitleMatchLinks.Add(link);
}
}
public virtual void RemoveEmployeeLink(EmployeeToJobTitleMatchLink link)
{
link.TheJobTitle = this;
if (this.MyJobTitleToEmployeeMatchLinks.Contains(link))
{
this.MyJobTitleToEmployeeMatchLinks.Remove(link);
}
if (link.TheEmployee.MyEmployeeToJobTitleMatchLinks.Contains(link))
{
link.TheEmployee.MyEmployeeToJobTitleMatchLinks.Remove(link);
}
}
}
public partial class EmployeeToJobTitleMatchLink
{
public EmployeeToJobTitleMatchLink()
{
//this.Id = Guid.NewGuid(); /* this works in conjuction with <generator class="assigned"></generator> */
}
public virtual Guid? LinkSurrogateUUID { get; set; }
/* These are "scalar properties of the ~~relationship~~ */
public virtual int PriorityRank { get; set; }
public virtual DateTime JobStartedOnDate { get; set; }
public virtual Employee TheEmployee { get; set; }
public virtual JobTitle TheJobTitle { get; set; }
}
Mappings:
public class EmployeeMap : ClassMap<Employee>
{
public EmployeeMap()
{
Id(x => x.EmployeeUUID).GeneratedBy.GuidComb();
OptimisticLock.Version();
Version(x => x.TheVersionProperty)
.Column("MyVersionColumn")
.Not.Nullable()
.CustomSqlType("timestamp")
.Generated.Always();
Map(x => x.SSN);
Map(x => x.LastName);
Map(x => x.FirstName);
Map(x => x.CreateDate);
Map(x => x.HireDate);
HasMany(x => x.MyEmployeeToJobTitleMatchLinks)
.Inverse()
.Cascade.All();
}
}
public class JobTitleMap : ClassMap<JobTitle>
{
public JobTitleMap()
{
Id(x => x.JobTitleUUID).GeneratedBy.GuidComb();
OptimisticLock.Version();
Version(x => x.TheVersionProperty)
.Column("MyVersionColumn")
.Not.Nullable()
.CustomSqlType("timestamp")
.Generated.Always();
Map(x => x.JobTitleName);
Map(x => x.CreateDate);
HasMany(x => x.MyJobTitleToEmployeeMatchLinks)
.Inverse()
.Cascade.All();
}
}
public class EmployeeToJobTitleMatchLinkMap : ClassMap<EmployeeToJobTitleMatchLink>
{
public EmployeeToJobTitleMatchLinkMap()
{
Id(x => x.LinkSurrogateUUID).GeneratedBy.GuidComb();
Map(x => x.PriorityRank);
Map(x => x.JobStartedOnDate);
References(x => x.TheEmployee).Column("TheEmployeeUUID").Not.Nullable();/*Bad naming convention with "The", but left here so it can be seen easily in the DDL*/
References(x => x.TheJobTitle).Column("TheJobTitleUUID").Not.Nullable();/*Bad naming convention with "The", but left here so it can be seen easily in the DDL*/
}
}
This works fine, but I'm getting 2 extra (nullable) columns in the ddl. They are marked with asteriks(*) below.
Select * From [dbo].[EmployeeToJobTitleMatchLink]
LinkSurrogateUUID
PriorityRank
JobStartedOnDate
TheEmployeeUUID
TheJobTitleUUID
*Employee_id
*JobTitle_id
I understand this is "by convention". (The names with the "_id" on them). But I don't need these columns. And I need to be able to have customized names. (TheEmployeeUUID and TheJobTitleUUID in this mock example.)
My end-game is to have:
Select * From [dbo].[EmployeeToJobTitleMatchLink]
LinkSurrogateUUID (UniqueIdentifier, SurrogateKey)
PriorityRank (scalar, int)
JobStartedOnDate (scalar,datetime)
TheEmployeeUUID (UniqueIdentifier, FK back to dbo.Employee.EmployeeUUID )
TheJobTitleUUID (UniqueIdentifier, FK back to dbo.JobTitle.JobTitleUUID )
The attribute(s) on the ~relationship are very important to keep. (PriorityRank and JobStartedOnDate in this mock up example.)
Thanks. I'm ~so close.
EDIT:
Mappings that work:
public class EmployeeMap : ClassMap<Employee>
{
public EmployeeMap()
{
Id(x => x.EmployeeUUID).GeneratedBy.GuidComb();
OptimisticLock.Version();
Version(x => x.TheVersionProperty)
.Column("MyVersionColumn")
.Not.Nullable()
.CustomSqlType("timestamp")
.Generated.Always();
Map(x => x.SSN);
Map(x => x.LastName);
Map(x => x.FirstName);
Map(x => x.CreateDate);
Map(x => x.HireDate);
HasMany(x => x.MyEmployeeToJobTitleMatchLinks)
.Inverse()
.Cascade.All()
.KeyColumn("TheEmployeeUUID")
;
}
}
public class JobTitleMap : ClassMap<JobTitle>
{
public JobTitleMap()
{
Id(x => x.JobTitleUUID).GeneratedBy.GuidComb();
OptimisticLock.Version();
Version(x => x.TheVersionProperty)
.Column("MyVersionColumn")
.Not.Nullable()
.CustomSqlType("timestamp")
.Generated.Always();
Map(x => x.JobTitleName);
Map(x => x.CreateDate);
HasMany(x => x.MyJobTitleToEmployeeMatchLinks)
.Inverse()
.Cascade.All()
.KeyColumn("TheJobTitleUUID")
;
}
}
public class EmployeeToJobTitleMatchLinkMap : ClassMap<EmployeeToJobTitleMatchLink>
{
public EmployeeToJobTitleMatchLinkMap()
{
Id(x => x.LinkSurrogateUUID).GeneratedBy.GuidComb();
Map(x => x.PriorityRank);
Map(x => x.JobStartedOnDate);
References(x => x.TheEmployee).Column("TheEmployeeUUID").Not.Nullable();/*Bad naming convention with "The", but left here so it can be seen easily in the DDL*/
References(x => x.TheJobTitle).Column("TheJobTitleUUID").Not.Nullable();/*Bad naming convention with "The", but left here so it can be seen easily in the DDL*/
}
}
Thanks Nathan!
PS One new term I learned while googling/binging myself was
"objectified relationship"
It was in the comments area of this page: LINK1
In case that page dies sometime in the future, here is that commented pasted in:
It’s called an ‘objectified relationship’ (ref: http://www.orm.net) and in NIAM/ORM it’s typically defined as a relationship which is on itself an entity with attributes. An objectified relationship is always forming at least one m:n relationship. (From http://weblogs.asp.net/fbouma/ )
I think you need to add a KeyColumn("key-name") as part of the HasMany mapping to both your JobTitleMap and EmplyeeMap. This is because fluent-nhibernate is using conventions to create the FK in the EmployeeToJobTitleMatchLink table. Using KeyColumn as part of the HasMay mapping should override the convention.
Something like the following :-
public class JobTitleMap : ClassMap<JobTitle>
{
public JobTitleMap()
{
Id(x => x.JobTitleUUID).GeneratedBy.GuidComb();
OptimisticLock.Version();
Version(x => x.TheVersionProperty)
.Column("MyVersionColumn")
.Not.Nullable()
.CustomSqlType("timestamp")
.Generated.Always();
Map(x => x.JobTitleName);
Map(x => x.CreateDate);
HasMany(x => x.MyJobTitleToEmployeeMatchLinks)
.Inverse()
.Cascade.All()
**.KeyColumn("TheJobTitleUUID")**
}
}
这篇关于流利的nhibernate - 多对多关系的属性关系的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!