使用生成的属性NHibernate备用ID

问题描述

| **此问题已过编辑,使其更简单,更集中** Employee有一个EmployeeNumberValue属性,我希望该属性数据库自动递增。对于业务域,这是分配给员工的唯一ID,用于在员工卡等上标识他们。但是,对于数据库,它是备用ID,而不是主键。 NHib具有记录的功能,称为“生成属性”。 根据文档,\“生成属性是具有其值由数据库生成属性。通常,NHibernate应用程序需要刷新对象,这些对象包含数据库为其生成值的任何属性。但是,将属性标记为已生成,则可以让应用程序委托本质上,每当NHibernate对已定义生成属性的实体发出sql INSERT或UPDATE时,NHibernate都会立即发出选择以检索生成的值。\“ 我遇到的问题是,尽管NHib进行了其他SELECT更新EmployeeNumberValue,但它没有将检索到的值分配给该属性。 谁能知道为什么会这样吗? 干杯, 贝里 失败的测试和输出(在内存数据库中通过sqlite进行了测试):
    [Test]
    public void Employee_OnInsert_EmployeeNumberValueIsIncremented() {

        var emp1 = new Employee
        {
            FullName = _fullName,Department = _department,};
        var emp2 = new Employee
        {
            FullName = _fullName,};

        var session = _SessionFactory.GetCurrentSession(); 

        using (var tx = session.BeginTransaction())
        {
            session.Save(_department);
            session.Save(emp1);
            session.Save(emp2);
            tx.Commit();
        }
        Assert.That(emp1.EmployeeNumberValue,Is.EqualTo(1));
        Assert.That(emp2.EmployeeNumberValue,Is.EqualTo(2));
    }

NHibernate: INSERT INTO Employees (FirstName,LastName,DepartmentId,EmployeeId) 
        VALUES (@p0,@p1,@p2,@p3);@p0 = \'Berryl\' [Type: String (0)],@p1 = \'Hesh\' [Type: String (0)],@p2 = 32768 [Type: Int32 (0)],@p3 = 65536 [Type: Int32 (0)]
NHibernate: SELECT employee_.EmployeeNumberValue as Employee2_1_ FROM Employees employee_ WHERE employee_.EmployeeId=@p0;@p0 = 65536 [Type: Int32 (0)]
NHibernate: INSERT INTO Employees (FirstName,@p3 = 65537 [Type: Int32 (0)]
NHibernate: SELECT employee_.EmployeeNumberValue as Employee2_1_ FROM Employees employee_ WHERE employee_.EmployeeId=@p0;@p0 = 65537 [Type: Int32 (0)]
Test Failed: 
   Expected: 1
   But was:  0
对象模型
public class Employee : Entity,IResource
{
    public virtual long EmployeeNumberValue { get; set; }

    ...
}
映射:
  <class name=\"Employee\" table=\"Employees\">

<id name=\"Id\" unsaved-value=\"0\">
  <column name=\"EmployeeId\" />
  <generator class=\"hilo\" />
</id>

<property name=\"EmployeeNumberValue\" generated=\"insert\" insert=\"false\" update=\"false\" >
  <column name=\"EmployeeNumberValue\" sql-type=\"int IDENTITY(1,1)\" index=\"IDX_EmployeeNumber\"  />      
</property>

...
create table Employees (
    EmployeeId INTEGER not null,EmployeeNumberValue int IDENTITY(1,1),FirstName TEXT not null,LastName TEXT not null,DepartmentId INTEGER,primary key (EmployeeId)
)
我怀疑将列标记为IDENTITY的方式也令人怀疑。我尝试如下使用数据库对象,但这样做时出现使用错误
  <database-object>
    <create>
      ALTER TABLE Employee DROP COLUMN EmployeeNumberValue
      ALTER TABLE Employee ADD EmployeeNumberValue INT IDENTITY
    </create>
    <drop>
      ALTER TABLE Employee DROP COLUMN EmployeeNumberValue
    </drop>
  </database-object>

sqliteException : sqlite error  \"DROP\": Syntax error
    

解决方法

        从设计的角度来看,在这种情况下,我不会依赖NHibernate。我的意思是,在您的域模型中,您希望员工获得新的员工卡号。 在这种情况下,如果有卡号,我将只允许员工实例化。
public class EmployeeCardNumber
{
    private string id = String.Empty;
    internal EmployeeCardNumber(string id)
    {
        this.id = id;
    }
}


public class Employee
{
    private EmployeeCardNumber employeeCardNumber;

    public EmployeeCardNumber CardNumber { ... }

    public Employee(EmployeeCardNumber employeeCardNumber)
    {
        this.employeeCardNumber = employeeCardNumber;
    }
}
因此,现在您必须考虑如何生成唯一的EmployeeCardNumber。
public class EmployeeCardNumberFactory
{
    public EmployeeCardNumber CreateNew()
    {
        // in this example the card number will be a guid.
        // but you could also implement a \"EmployeeCardNumberGenerator\" class which will do crazy database stuff
        return new EmployeeCardNumber(Guid.NewGuid().ToString());
    }
}
然后,您以后会做:
EmployeeCardNumber cardNumber = employeeCardNumberFactory.CreateNew();
Employee employee = new Employee(cardNumber,name,etc...);
加成: 要通过数据库生成\“ EmployeeCardNumber \”,您可以将\“ EmployeeCardNumber \”映射到一个额外的表\“ EmployeeCardNumber \”,该表将用作您的身份生成器,例如:
<class name=\"EmployeeCardNumber\" table=\"EmployeeCardNumber\">
    <id name=\"id\" access=\"field\" unsaved-value=\"0\">
      <column name=\"EmployeeCardNumberId\" />
      <generator class=\"identity\" />
    </id>
</class>
然后在工厂中,您可以执行以下操作:
public class EmployeeCardNumberFactory
{
    private IEmployeeCardNumberRepository repository = new EmployeeCardNumberRepository(); // inject...
    public EmployeeCardNumber CreateNew()
    {     
        EmployeeCardNumber cardNumber = new EmployeeCardNumber();
        repository.Save(cardNumber); // gets you a fresh id
        return cardNumber;
    }
}
    ,        尽管这是可行的,但最好在数据库中执行此操作(使用标识或触发器),并映射插入时生成的属性。 检查5.5。生成的属性     ,        我有同样的情况,在生产中效果很好。 这是映射(由Fluent NHibernate生成):
<property generated=\"insert\" name=\"Number\" update=\"false\" type=\"System.Int32,mscorlib,Version=4.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089\">
  <column name=\"Number\" not-null=\"true\" />
</property>
在数据库中,此列如下所示:
ALTER TABLE [DeviceLink] ADD [Number] INT not null IDENTITY (1,1)
    

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...