流利的nhibernate - 多对多关系的属性关系 [英] fluent nhibernate - Many to Many relationship with attribute on relationship

查看:162
本文介绍了流利的nhibernate - 多对多关系的属性关系的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有我的代码工作,但我在表/ 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆