如何使用FluentNHibernate N:N与其他属性

时间:2017-07-19 19:10:01

标签: c# sql sql-server nhibernate fluent-nhibernate

我有这个数据库模型:

Candidato 1< - > N Telefone N< - > 1 TipoTelefone

我的表有哪些列

Candidato

  • Id(int - identity)
  • NomeCompleto
  • DataNascimento

Telefone

  • Id(int - identity)
  • IdCandidato
  • IdTipoTelefone
  • NÚMERO

TipoTelefone

  • Id(int - identity)
  • 诺姆

我的课程属性是:

Candidato
=========
public virtual int Id { get; set; }
public virtual string NomeCompleto { get; set; }
public virtual DateTime DataNascimento { get; set; }
public virtual IList<Telefone> Telefones { get; set; }

Telefone
========
public virtual int Id { get; set; }
public virtual Candidato Candidato { get; set; }
public virtual TipoTelefone TipoTelefone { get; set; }
public virtual string Numero { get; set; }

TipoTelefone
============
public virtual int Id { get; set; }
public virtual string Descricao { get; set; }
public IList<Telefone> Telefones { get; set; }

我正在尝试保存Candidato及其Telefones,因为我有许多Telefones的Candidato。

但是当我尝试同时保存我的Candidato及其Telefones时,我遇到了错误。下面我每次尝试某种尝试时都会遇到一些错误:

  • 对象引用未保存的瞬态实例 - 在刷新之前保存瞬态实例,或者将属性的级联操作设置为使其自动保存的操作。键入:Entity.Telefone,Entity:Entity.Telefone

  • object是未保存的瞬态实例 - 在合并之前保存瞬态实例:Entity.Telefone

  • 该类没有标识符属性:Entity.Telefone

  • 当IDENTITY_INSERT设置为OFF时,无法在表'Telefone'中为identity列插入显式值。

  • Nãoé能转换器um objeto do tipo'NHibernate.Collection.Generic.PersistentGenericSet 1[Entity.Telefone]' no tipo 'System.Collections.Generic.IList 1 [Entity.Telefone]'。

  • 对象引用未保存的瞬态实例 - 在刷新之前保存瞬态实例,或者将属性的级联操作设置为使其自动保存的操作。键入:Entity.Telefone,Entity:Entity.Telefone

  • 无法插入:[Entity.Telefone] [SQL:INSERT INTO Telefone(Numero,IdTipoTelefone,Id)VALUES(?,?,?);选择SCOPE_IDENTITY()]

我的项目正在使用NHibernate.Mapping.ByCode,但我怀疑我没有得到正确的地图解决方案。所以,我想知道,如何为这三个实体做出正确的映射。

重要的是要看到我的N:N Telefone表有一个属性Numero,所以这个实体/表不是一个简单的N:N实体,而是一个真实的实体,因为它里面有一个自己的属性。

1 个答案:

答案 0 :(得分:0)

这是我的一个老例子。

这是我的“中间”表。

这是一张流利地图

public class EmployeeToJobTitleMatchLinkMap : ClassMap<EmployeeToJobTitleMatchLinkNHEntity>
{

    public EmployeeToJobTitleMatchLinkMap()
    {

        Schema("dbo");
        Table("EmployeeToJobTitleMatchLink");

        Id(x => x.LinkSurrogateUUID).GeneratedBy.GuidComb();
        Map(x => x.PriorityRank);
        Map(x => x.JobStartedOnDate);

        References(x => x.TheEmployee).Column("TheEmployeeUUID").Not.Nullable().Index("IX_ETJTMLM_TheEmployeeUUID_And_TheJobTitleUUID"); ;/*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().Index("IX_ETJTMLM_TheEmployeeUUID_And_TheJobTitleUUID"); ;/*Bad naming convention with "The", but left here so it can be seen easily in the DDL*/

    }
}

这是(我认为与上面相同)作为hbm.xml文件。

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class xmlns="urn:nhibernate-mapping-2.2" schema="dbo" name="MyCompany.MyTechnology.Prototypes.CompositeAppPOC.Data.NHibernateSetup.Domain.EmployeeToJobTitleMatchLinkNHEntity, MyCompany.MyTechnology.Prototypes.CompositeAppPOC.Data.NHibernateSetup, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="EmployeeToJobTitleMatchLink">
    <id name="LinkSurrogateUUID" type="System.Nullable`1[[System.Guid, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="LinkSurrogateUUID" />
      <generator class="guid.comb" />
    </id>
    <property name="PriorityRank" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="PriorityRank" />
    </property>
    <property name="JobStartedOnDate" type="System.DateTime, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="JobStartedOnDate" />
    </property>
    <many-to-one class="MyCompany.MyTechnology.Prototypes.CompositeAppPOC.Data.NHibernateSetup.Domain.EmployeeNHEntity, MyCompany.MyTechnology.Prototypes.CompositeAppPOC.Data.NHibernateSetup, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" name="TheEmployee">
      <column name="TheEmployeeUUID" index="IX_ETJTMLM_TheEmployeeUUID_And_TheJobTitleUUID" not-null="true" />
    </many-to-one>
    <many-to-one class="MyCompany.MyTechnology.Prototypes.CompositeAppPOC.Data.NHibernateSetup.Domain.JobTitleNHEntity, MyCompany.MyTechnology.Prototypes.CompositeAppPOC.Data.NHibernateSetup, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" name="TheJobTitle">
      <column name="TheJobTitleUUID" index="IX_ETJTMLM_TheEmployeeUUID_And_TheJobTitleUUID" not-null="true" />
    </many-to-one>
  </class>
</hibernate-mapping>

PriorityRank和JobStartedOnDate将是我“关系中的额外属性”。

这是我找到的另一个hbm.xml文件。

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   assembly="MyCompany.MyTechnology.Prototypes.CompositeAppPOC.Glue"
                   namespace="MyCompany.MyTechnology.Prototypes.CompositeAppPOC.Glue.Domain">

  <class name="EmployeeToJobTitleMatchLink" lazy="false" schema="MySchema">

    <!-- Naming this "Id" might be a requirement, be careful -->


    <!-- 
      ISSUE If the generator class is changed from "assigned" to 
      guid
      guid.comb
      uuid.string

      It will break the ability to create the relationship

    -->


    <id name="LinkSurrogateUUID">
      <generator class="guid.comb"></generator>
    </id>

    <!-- 
    <id name="LinkSurrogateKey">
      <!- -
      <generator class="hilo">
            <param name="table">HiloHolder</param>
        <param name="column">HiloColumn</param>
      </generator>
      - ->
      <generator class="identity">
      </generator>
    </id>
    -->

    <many-to-one name="TheEmployee" column="EmployeeUUID" lazy="false" cascade="none" not-null="true" /> <!-- class="MyCompany.MyTechnology.Prototypes.CompositeAppPOC.Glue.Domain.Employee, MyCompany.MyTechnology.Prototypes.CompositeAppPOC.Glue" -->
    <many-to-one name="TheJobTitle" column="JobTitleUUID" lazy="false" cascade="none" not-null="true" /> <!-- class="MyCompany.MyTechnology.Prototypes.CompositeAppPOC.Glue.Domain.JobTitle, MyCompany.MyTechnology.Prototypes.CompositeAppPOC.Glue" -->

    <!-- 
    <many-to-one name="TheEmployee" column="EmployeeKey" lazy="false" cascade="none" not-null="true" /> 
    <many-to-one name="TheJobTitle" column="JobTitleKey" lazy="false" cascade="none" not-null="true" /> 
    -->

    <!-- These are "scalar properties of the ~relationship~"-->
    <property name="PriorityRank" not-null="true" update="false"  />
    <property name="JobStartedOnDate" not-null="true" update="false" />

  </class>

</hibernate-mapping>

这是我的“中间”域对象

[Serializable]
public partial class EmployeeToJobTitleMatchLink
{
    public EmployeeToJobTitleMatchLink()
    {
        //this.Id = Guid.NewGuid(); /* this works in conjuction with <generator class="assigned"></generator>   */
    }


    //EF Tweaks
    public Guid TheEmployeeUUID { get; set; }
    public Guid TheJobTitleUUID { get; set; }

    public Guid? LinkSurrogateUUID { get; set; }

    /*  These are "scalar properties of the ~~relationship~~  */
    public int PriorityRank { get; set; }
    public DateTime JobStartedOnDate { get; set; }

    public Employee TheEmployee { get; set; }
    public JobTitle TheJobTitle { get; set; }
}

也许这会有所帮助。

我一度解决了这个问题,但现在已经好几年了。

关键是你有一个域对象,它有额外的标量和每个“边”的单个对象。

Telefone
========
public virtual int Id { get; set; }
public virtual Candidato Candidato { get; set; }
public virtual TipoTelefone TipoTelefone { get; set; }
public virtual string Numero { get; set; }

我相信你的Telefone课程是正确的。所以我认为问题在于您的映射。 Fluent或hbm.xml。也许我的“笔记”可以提供帮助。我不能把这个放在评论中。

我有一些巫术,我必须将“中间”对象添加到“外部”对象。

例如:

{
    [Serializable]
    public partial class Employee 
    {

        public Employee()
        {
            CommonConstructor();
        }
        private void CommonConstructor()
        {
            this.MyEmployeeToJobTitleMatchLinks = new EmployeeToJobTitleMatchLinkCollection();
        }



        //EF Tweaks
        public Guid ParentDepartmentUUID { get; set; }


        public Guid? EmployeeUUID { get; set; }

        public byte[] TheVersionProperty { get; set; }

        //public int? EmployeeKey { get; set; }



//        public IDepartment ParentDepartment { get; set; }

        public string SSN { get; set; }
        public string LastName { get; set; }
        public string FirstName { get; set; }
        public DateTime CreateDate { get; set; }
        public DateTime HireDate { get; set; }
        //



        public EmployeeToJobTitleMatchLinkCollection MyEmployeeToJobTitleMatchLinks { get; set; }




        public 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 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 ICollection<IParkingAreaDeprecated> MyParkingAreas { get; set; }
        //public ICollection<ParkingArea> MyParkingAreas { get; set; }
        public IParkingAreaCollection MyParkingAreas { get; set; }





        //public void AddParkingArea(IParkingAreaDeprecated pa)
        public void AddParkingArea(ParkingArea pa)
        {
            //pa.MyEmployees.Add(this);
            if (!pa.MyEmployees.Contains(this))
            {
                //pa.AddEmployee(this);//Causes overflow situation
                pa.MyEmployees.Add(this);
            }
            if (!this.MyParkingAreas.Contains(pa))
            {
                this.MyParkingAreas.Add(pa);
            }
        }

        //public void RemoveParkingArea(IParkingAreaDeprecated pa)
        public void RemoveParkingArea(ParkingArea pa)
        {
            if (pa.MyEmployees.Contains(this))
            {
                pa.MyEmployees.Remove(this);
            }
            if (this.MyParkingAreas.Contains(pa))
            {
                this.MyParkingAreas.Remove(pa);
            }
        }


        public override string ToString()
        {
           return string.Format("{0}:{1},{2}", this.SSN , this.LastName , this.FirstName );
        }



    }




}

和另一个“外部”对象

   [Serializable]
    public partial class JobTitle : IJobTitle
    {

        public JobTitle()
        {
            CommonConstructor();
        }
        private void CommonConstructor()
        {
            //this.MyEmployees = new List<Employee>();
            //this.MyJobTitleToEmployeeMatchLinks = new List<EmployeeToJobTitleMatchLink>();
            this.MyJobTitleToEmployeeMatchLinks = new EmployeeToJobTitleMatchLinkCollection();
        }

        public Guid? JobTitleUUID { get; set; }
        //public int? JobTitleKey { get; set; }


        //public byte[] TheVersionProperty { get; set; }


        public string JobTitleName { get; set; }
        public DateTime CreateDate { get; set; }

        //public ICollection<Employee> MyEmployees { get; set; }
        //public ICollection<IEmployeeToJobTitleMatchLink> MyJobTitleToEmployeeMatchLinks { get; set; }
        //public ICollection<EmployeeToJobTitleMatchLink> MyJobTitleToEmployeeMatchLinks { get; set; }
        public IEmployeeToJobTitleMatchLinkCollection MyJobTitleToEmployeeMatchLinks { get; set; }


        public 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 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);
            }

        }

    }
}

这是我编写所有内容的代码。

注意,我有一个我以前没有讨论的部门实体。 重要的部分是Employee,JobTitle和“link”对象

            EmployeeController empRepo = null;
            JobTitleController jtRepo = null;

            Department idept = new Department() { DepartmentName = "Department One", CreateDate = DateTime.Now };
            DepartmentController deptRepo = new DepartmentController();
            deptRepo.Add(idept);

            Employee emp = new Employee() { ParentDepartment = idept, SSN = "111111111", CreateDate = DateTime.Now, HireDate = DateTime.Now, LastName = "Smith", FirstName = "John" };
            JobTitle jtDev = new JobTitle() { JobTitleName = "Developer", CreateDate = DateTime.Now };
            JobTitle jtProjectManager = new JobTitle() { JobTitleName = "Project Manager", CreateDate = DateTime.Now };
            JobTitle jtDba = new JobTitle() { JobTitleName = "DBA", CreateDate = DateTime.Now };

            jtRepo = new JobTitleController();
            jtRepo.Add(jtDev);
            jtRepo.Add(jtProjectManager);

            empRepo = new EmployeeController();
            empRepo.AddEmployee(emp);

            EmployeeToJobTitleMatchLink link1ToAddThruJobTitleObject = new EmployeeToJobTitleMatchLink();
            link1ToAddThruJobTitleObject.TheEmployee = emp;
            link1ToAddThruJobTitleObject.TheJobTitle = jtDba;
            link1ToAddThruJobTitleObject.JobStartedOnDate = DateTime.Now.AddDays(-1);
            link1ToAddThruJobTitleObject.PriorityRank = 5;

            jtDba.AddEmployeeLink(link1ToAddThruJobTitleObject);

            jtRepo.Add(jtDba);

            EmployeeToJobTitleMatchLink link1ToAddThruEmployeeObject = new EmployeeToJobTitleMatchLink();
            link1ToAddThruEmployeeObject.TheEmployee = emp;
            link1ToAddThruEmployeeObject.TheJobTitle = jtDev;
            link1ToAddThruEmployeeObject.JobStartedOnDate = DateTime.Now.AddHours(-1);
            link1ToAddThruEmployeeObject.PriorityRank = 1;

            EmployeeToJobTitleMatchLink link2ToAddThruEmployeeObject = new EmployeeToJobTitleMatchLink();
            link2ToAddThruEmployeeObject.TheEmployee = emp;
            link2ToAddThruEmployeeObject.TheJobTitle = jtProjectManager;
            link2ToAddThruEmployeeObject.JobStartedOnDate = DateTime.Now.AddYears(5);
            link2ToAddThruEmployeeObject.PriorityRank = 2;

            emp.AddJobTitleLink(link1ToAddThruEmployeeObject);
            emp.AddJobTitleLink(link2ToAddThruEmployeeObject);

            empRepo.Upsert(emp);