Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/mongodb/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用生成的属性的nhibernate备用id_Nhibernate_Identity_Sequences - Fatal编程技术网

使用生成的属性的nhibernate备用id

使用生成的属性的nhibernate备用id,nhibernate,identity,sequences,Nhibernate,Identity,Sequences,**对该问题进行了编辑,使其更简单、更集中** Employee有一个EmployeeNumberValue属性,我希望该属性由db自动递增。对于业务域而言,这是分配给员工的唯一id,用于在员工卡上识别员工。但是,对于数据库而言,这是一个备用id,而不是主键 NHib有一个记录在案的能力叫做。 根据文档,生成的属性是由数据库生成其值的属性。通常,NHibernate应用程序需要刷新包含数据库正在为其生成值的任何属性的对象。但是,将属性标记为已生成可以让应用程序将此职责委托给NHibernate。

**对该问题进行了编辑,使其更简单、更集中**

Employee有一个EmployeeNumberValue属性,我希望该属性由db自动递增。对于业务域而言,这是分配给员工的唯一id,用于在员工卡上识别员工。但是,对于数据库而言,这是一个备用id,而不是主键

NHib有一个记录在案的能力叫做。 根据文档,生成的属性是由数据库生成其值的属性。通常,NHibernate应用程序需要刷新包含数据库正在为其生成值的任何属性的对象。但是,将属性标记为已生成可以让应用程序将此职责委托给NHibernate。本质上,每当NHibernate为已定义生成属性的实体发出SQL INSERT或UPDATE时,它会立即在之后发出select以检索生成的值

我遇到的问题是,当NHib进行额外选择以更新EmployeeNumber值时,它没有将检索到的值分配给属性

有人知道为什么会发生这种情况吗?解决办法是什么

干杯, 贝里尔

在内存数据库中使用SQLite进行测试和输出测试失败:

    [Test]
    public void Employee_OnInsert_EmployeeNumberValueIsIncremented() {

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

        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, LastName, DepartmentId, EmployeeId) 
        VALUES (@p0, @p1, @p2, @p3);@p0 = 'Berryl' [Type: String (0)], @p1 = 'Hesh' [Type: String (0)], @p2 = 32768 [Type: Int32 (0)], @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>

...
我怀疑我将专栏标记为身份的方式也值得怀疑。我尝试使用数据库对象,如下所示,但在使用过程中出现了使用错误

  <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

虽然这是可行的,但最好在数据库中使用identity或触发器并映射insert时生成的属性


检查

我有相同的场景,它在生产中运行得非常好

以下是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>

从设计角度来看,在这种情况下,我不会依赖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;
    }
}
在这种情况下,我只允许在有卡号的情况下实例化员工

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>

谢谢你的回复——我问这个问题的动机是双重的。首先,我认为侦听器/拦截器方法可以避免额外的选择。其次,我尝试使用生成的代码似乎不起作用。请参阅我的最新帖子评论/mapping@Berryl:如果没有选择,您将如何操作?即使使用原始ADO.NET,这也是不可能的,除非您假设很多,并使用一些讨厌的锁,或者在select语句中使用查询;另一篇SO帖子暗示它可以通过拦截器完成,但没有说明如何完成。您的属性真的命名为Value而不是EmployeeNumber吗?这应该有效:。你做了列标识吗?@Diego最后一点是个问题,所以我改变了映射,使之成为列标识,如修改后的映射所示。我可能仍然对属性感到困惑,因为没有赋值。Employee有一个名为EmployeeNumber的属性,该属性本身是一个值对象组件,它有一个名为value的属性。@Diego-创建列标识也有点棘手。你有不同的使用方法吗?@Berryl:为什么要使用组件和ValueObject继承,以及所有这些东西?只要在Employee中使用一个简单的公共虚拟long EmployeeNumber{get;set;}和我给您的映射,它就会工作。@Diego:将它作为一个对象,可以很容易地格式化显示值。对于ProjectNumber,我有一个更复杂但类似的情况,它应该通过前缀自动递增,重点是我希望能够解决组件的情况。你能想到我还能尝试什么吗?这更接近我的偏好,正如你从中看到的,似乎没有人感兴趣。我也喜欢用一个单独的表来生成顺序ID的想法,尽管我仍然想知道为什么文档化生成的属性在这里不起作用。你在项目中实际使用过这样的模式吗?是的,当然,这或多或少是领域驱动的设计。虽然像自动生成的数据库id这样的人工id毫无意义,并且仅用于技术目的、连接、引用完整性,这是创建实体唯一标识的唯一方法,但您的卡号在您的业务域中用于特定的业务目的。这就是为什么应该像在域模型中那样对其进行明确建模。我在上面的模式中看到的唯一缺点是,现在可能有两名员工拥有相同的卡号。为了解决这个问题,EmployeeCardNumber应该只与员工一起实例化。对此不太确定-添加当然可以取消。看起来这里的诀窍更多的是保存,也许将数字指定为p 交易的艺术。
<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;
    }
}