我正在开发一个使用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")
但我不能这样做。反正有吗?
答案 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生成器问题。