是否可以从标量函数的结果中为Id分配默认值

时间:2016-04-26 01:53:06

标签: c# mysql .net nhibernate fluent-nhibernate

我正在开发一个使用NHibernate和Fluent NHibernate进行映射的.NET Web api应用程序。

我有一个名为“next_photo_id()”的标量函数生成Int64数字之类的 Sharding & IDs at Instagram

但是我无法将标量函数作为默认值分配给Mysql中的Id列。我试过了,我得到了错误。

ALTER TABLE `photos`
    CHANGE COLUMN `id` `id` BIGINT(20) NOT NULL DEFAULT next_photo_id() FIRST ;

所以我尝试使用fluentNhibernate从Application端分配Id。

我的照片表的类图是

 public class PhotoMap : ClassMap<Photo>
{
    public PhotoMap()
    {
        Table("photos");


        Id(m => m.Id).Column("id").Access.Property().Default("next_photo_id()");

        Map(m => m.Caption).Column("caption");
    }
 }

照片表插入查询必须是,

Insert Into photos (id,caption) values (next_photo_id(),"test")

但我不能这样做。反正有吗?

1 个答案:

答案 0 :(得分:1)

在映射中定义默认值仅适用于DDL。基本上,你刚刚告诉NHibernate尝试定义默认的SQL约束,以防你要求它为你生成数据库模式。 (它与您尝试在SQL中直接定义的那个相同。)

对于您的情况,您需要定义自定义插入查询。我知道如何使用hbm.xml映射,它记录在here,它将类似于:

<class name="PhotoMap" table="photos">
    ...

    <sql-insert>insert into photos (caption, id)
      values (?,
        case when ? is null then next_photo_id() else next_photo_id() end)
    </sql-insert>
</class>

如记录所述,您应首先确定NHibernate以何种顺序发送其参数并坚持此订单。而且,NHibernate会期望id的位置参数,如果没有它就会失败。所以我使用case来解决它。您可以通过使用接受所有参数的存储过程更干净地处理它,哪个主体将忽略id个。

为了将其翻译成Fluent NHibernate,我不知道,我不使用它。

现在你仍然需要克服一个主要障碍:你应该为你的id领域使用什么生成器?我没有看到任何适合的东西。您可能会对NHibernate撒谎,并告诉它类似assigned,但它不会为您检索db侧生成的id。如果您有一些自然ID可以找到它,则必须清除会话并查询新添加的照片...

否则,您必须实施custom id generator来支持您的案例。它应该是身份的一部分。但要注意,这一个as documented会导致sql-insert被忽略。实现自定义生成器时可能会遇到同样的问题。

如果您的id是一个简单的属性,而不是实体ID,那么您可以简单地告诉NHibernate它是generated

<property name="Id" generated="insert" />

但对于id,如上所述,据我所知,这种方式更为复杂。

数据库端

您的默认值应该在db中可行。使用SQL Server,定义默认值的正确方法如下:

alter table photos add constraint DefPhotosId default (dbo.next_photo_id()) for Id

如果在尝试定义默认值时发生错误,则应该打开一个mysql问题。

但无论如何,你仍然会在NHibernate方面遇到id生成器问题。