nhibernate 备用 id 使用生成的属性
** 这个问题已被编辑,使其更简单、更集中 **
Employee 有一个 EmployeeNumberValue 属性,我希望数据库自动递增该属性。对于业务领域来说,这是分配给员工的唯一ID,用于在员工卡等上识别他们。但是对于数据库来说,这是一个备用ID,而不是主键。
NHib 有一个记录在案的功能,称为生成的属性。 根据文档,“生成的属性是其值由数据库生成的属性。通常,NHibernate 应用程序需要刷新包含数据库为其生成值的任何属性的对象。但是,将属性标记为已生成,可以让应用程序委托此操作本质上,每当 NHibernate 对已定义生成属性的实体发出 SQL INSERT 或 UPDATE 时,它会立即发出选择来检索生成的值。”
我遇到的问题是,当 NHib 进行额外的 SELECT 来更新 EmployeeNumberValue 时,它没有将检索到的值分配给该属性。
谁能明白为什么会发生这种情况,解决办法是什么?
干杯,
Berryl
失败的测试和输出(在内存数据库中使用 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>
...
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
** This question has been edited to make it simpler and more focused **
Employee has an EmployeeNumberValue property which I would like to have auto-incremented by the db. To the business domain, this is a unique id assigned to employees and used to identify them on employee cards, etc. To the database however, it is an alternate id and not the primary key.
NHib has a documented ability called Generated Properties.
Per the docs, "generated properties are properties which have their values generated by the database. Typically, NHibernate applications needed to Refresh objects which contain any properties for which the database was generating values. Marking properties as generated, however, lets the application delegate this responsibility to NHibernate. Essentially, whenever NHibernate issues an SQL INSERT or UPDATE for an entity which has defined generated properties, it immediately issues a select afterwards to retrieve the generated values."
The problem I am having is that while NHib is making the additional SELECT to update the EmployeeNumberValue, it is not assigning the retrieved value to the property.
Can anyone see why this is happening what the fix is?
Cheers,
Berryl
FAILING TEST AND OUTPUT (tested w/ SQLite in memory db):
[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
OBJECT MODEL
public class Employee : Entity, IResource
{
public virtual long EmployeeNumberValue { get; set; }
...
}
MAPPING:
<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)
)
I suspect the way I am marking the column as IDENTITY is also suspect. I tried using database-object as below, but got a usage error in doing so
<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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
虽然这是可行的,但最好在数据库中执行此操作(使用身份或触发器)并映射插入时生成的属性。
检查5.5。生成的属性
While that's doable, it's better to do it in the DB (using identity or a trigger) and map the property as generated on insert.
Check 5.5. Generated Properties
从设计的角度来看,在这种情况下我不会依赖 NHibernate。我的意思是,在您的域模型中,您希望员工获得新的员工卡号。
在这种情况下,如果有卡号,我只会允许实例化员工。
所以现在你要考虑如何生成一个唯一的EmployeeCardNumber。
然后你稍后会做:
添加:
要通过数据库生成“EmployeeCardNumber”,您可以将“EmployeeCardNumber”映射到一个额外的表“EmployeeCardNumber”,该表将用作您的身份生成器,如下所示:
然后在工厂中您可以执行以下操作:
From a design perpective I wouldn't rely on NHibernate in this case. What I mean is, that in your domain model, you want an employee to get a new employee card number.
In this case I would only allow an employee to be instantiated if there is a card number.
So now you have to think about how to generate a unique EmployeeCardNumber.
Then you would later do:
Addition:
To generate a "EmployeeCardNumber" via database, you could just map "EmployeeCardNumber" to an extra table "EmployeeCardNumber" that will serve as your identity generator like:
Then in the factory you could do:
我有同样的场景,并且它在生产中运行得很好。
这是映射(由 Fluent NHibernate 生成):
在数据库中,此列如下所示:
I had same scenario and it works very well in production.
Here is mapping (generated by Fluent NHibernate):
In database this column looks like this: