是否可以从标量函数的结果中为 Id 分配默认值
Is It Possible to Assign Default value to Id from Result of Scalar Function
我正在开发 .NET Web api 应用程序,它使用 NHibernate 和 Fluent NHibernate 进行映射。
我有一个名为 "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 从应用程序端分配 Id。
我的照片 table 的类图是
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");
}
}
图片table插入查询必须,
Insert Into photos (id,caption) values (next_photo_id(),"test")
但是我做不到。有办法吗?
在映射中定义默认值仅适用于 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
的内容,但它不会为您检索在数据库端生成的 id
。如果您有一些 natural-id 来找到它,您将必须清除会话并查询新添加的照片...
否则,您必须执行 custom id generator for supporting your case. It should be something near the identity one. But beware, this one, as documented,导致 sql-insert
被忽略。您在实现自定义生成器时可能会遇到同样的问题。
如果您的 id
是一个简单的 属性,而不是实体 ID,您可以简单地告诉 NHibernate 它是 generated:
<property name="Id" generated="insert" />
但是对于 id,如上所述,据我所知,这要复杂得多。
数据库端
你的默认值应该在数据库中可行。使用 SQL 服务器,定义默认值的正确方法如下:
alter table photos add constraint DefPhotosId default (dbo.next_photo_id()) for Id
如果在尝试定义默认值时出现错误,您应该提出一个 mysql 问题。
但是无论如何,您仍然会在 NHibernate 端遇到 id 生成器问题。
我正在开发 .NET Web api 应用程序,它使用 NHibernate 和 Fluent NHibernate 进行映射。
我有一个名为 "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 从应用程序端分配 Id。
我的照片 table 的类图是
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");
}
}
图片table插入查询必须,
Insert Into photos (id,caption) values (next_photo_id(),"test")
但是我做不到。有办法吗?
在映射中定义默认值仅适用于 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
的内容,但它不会为您检索在数据库端生成的 id
。如果您有一些 natural-id 来找到它,您将必须清除会话并查询新添加的照片...
否则,您必须执行 custom id generator for supporting your case. It should be something near the identity one. But beware, this one, as documented,导致 sql-insert
被忽略。您在实现自定义生成器时可能会遇到同样的问题。
如果您的 id
是一个简单的 属性,而不是实体 ID,您可以简单地告诉 NHibernate 它是 generated:
<property name="Id" generated="insert" />
但是对于 id,如上所述,据我所知,这要复杂得多。
数据库端
你的默认值应该在数据库中可行。使用 SQL 服务器,定义默认值的正确方法如下:
alter table photos add constraint DefPhotosId default (dbo.next_photo_id()) for Id
如果在尝试定义默认值时出现错误,您应该提出一个 mysql 问题。
但是无论如何,您仍然会在 NHibernate 端遇到 id 生成器问题。