NHibernate ID已分配或本机

时间:2013-10-09 17:01:01

标签: c# nhibernate nhibernate-mapping primary-key

有没有办法在NHibernate中以一种可以同时分配或本机的方式映射实体的主键,并通过存储过程执行插入和更新操作?这样,如果Id具有未分配的值,则它将在存储过程中本机生成,如果它具有不同的值,则它将保持指定的值。

2 个答案:

答案 0 :(得分:1)

我认为您的ID生成听起来非常自定义,因此可以编写自定义生成器,然后可以在您的映射中使用。

查找如何implement a custom generator here的一些示例。

基本上它看起来像这样

public class FDPSequence : TableGenerator
{
    private const Int32 SeedValue = 1048576;

    public override object Generate(ISessionImplementor session, object obj)
    {
        int counter = Convert.ToInt32(base.Generate(session, obj));
        return counter + SeedValue + 1;
    }
}

在您的方案中,您可能希望在某些情况下使用NativeGenerator并在其他情况下调用SP ...

答案 1 :(得分:0)

经过一些测试后,我发现您可以将同一列映射到同一属性两次,一个是本地生成的Id,另一个是公共属性,但不可更新。第一个允许NHibernate从数据库中获取Id值,第二个允许将Id值传递给数据库,但仅在插入时,防止因插入后属性修改而对同一事务进行额外更新。

这是Fluent NHibernate映射:

public class ItemMap : ClassMap<Item>
{
    public ItemMap()
    {
        Schema("dbo");
        Table("Item");
        Id(x => x.IdItem, "idItem").UnsavedValue(0).GeneratedBy.Native();
        Map(x => x.IdItem, "idItem").Not.Update();
        Map(x => x.AnotherBoringField, "anotherBoringField");

        SqlInsert("EXEC [dbo].[StpInsertItem] @idItem=@p0, @anotherBoringField=@p1");
    }
}

存储过程:

CREATE PROCEDURE [dbo].[StpInsertItem]
  @idItem             INT,
  @anotherBoringField VARCHAR(10)
AS
BEGIN
  IF (@idItem = 0)
    BEGIN
      SELECT @idItem = MAX(idItem) + 1 FROM [dbo].[Item];
    END

    INSERT INTO [PT].[TblDBItem] (idItem, anotherBoringField)
    VALUES (@idItem, @anotherBoringField);

    SELECT @idItem id;
END
GO

请注意,存储过程总是执行ID的选择,即使它没有生成它,因为由于映射,NHibernate总是希望从数据库中检索ID。