次のようなvarchar列とnvarcharmax列を持つSQLServerテーブルがあります。
CREATE TABLE [dbo].[MyTable](
:
[MyBigUnicodeColumn] [nvarchar](max) NULL,
[MyBigAnsiColumn] [varchar](max) NULL,
:
マッピング(hbm.xml)ファイルを作成するとき、 documentation は、データベースタイプがDbType.Stringのラージオブジェクトのタイプ属性としてStringClobを使用するように指示しますが、次の場合の対処方法は指示しません。データベースタイプはDbType.AnsiStringです。
<class name="MyTable" table="MyTable" lazy="false">
:
<property name="MyBigUnicodeColumn" type="StringClob" />
<property name="MyBigAnsiColumn" type="????" />
:
これはNHibernate3.3.1用です。
string
またはAnsiString
のようにマップできます。
<property name="MyBigUnicodeColumn" type="string" length="1000000"/>
<property name="MyBigAnsiColumn" type="AnsiString" length="1000000" />
長さがそれぞれ4000または8000より大きい場合は常に、NHはnvarchar(max)またはvarchar(max)を作成します。
長さがSQLパラメータに使用され、指定された長さに切り捨てられている可能性があります(使用しているNHバージョンによって異なりますが、いくつかの変更がありました)。したがって、十分な大きさで指定することをお勧めします。
Edit:残念ながら、通常の文字列と同じようにAnsiStringでは機能しません。 NHコードを読んだところ、次のことがわかりました。
varchar(max)は、SQL Server2005以降の方言でサポートされています。
MsSql2000Dialect.cs、205行目
RegisterColumnType(DbType.AnsiString, SqlClientDriver.MaxSizeForLengthLimitedAnsiString, "VARCHAR($l)");
MsSql2005Dialect.cs、19行目:
RegisterColumnType(DbType.AnsiString, SqlClientDriver.MaxSizeForAnsiClob, "VARCHAR(MAX)");
これは、AnsiStringが8000より大きくマップされるときに選択するSQLタイプとしてvarchar(max)を登録します。
SqlClientDriver.csでは、文字列のパラメータに「blobs」が実装されているが、ansi文字列には実装されていないことがわかります(135行目)。
case DbType.AnsiString:
case DbType.AnsiStringFixedLength:
dbParam.Size = MaxSizeForLengthLimitedAnsiString;
break;
// later on
case DbType.String:
case DbType.StringFixedLength:
dbParam.Size = IsText(dbParam, sqlType) ? MaxSizeForClob : MaxSizeForLengthLimitedString;
break;
AnsiString型のパラメーターの制限として常に8000を設定します。
ドライバーと方言の間に矛盾があるので、私はそれをバグと呼ぶでしょう。
バグはすべてのAnsiStringで発生するため、マッピングでsql-typeを指定することは役に立ちません(NHは正しいsqlタイプを選択できます)。 NHフォーラムで開始したスレッド で提案されている回避策を使用する必要があります。
<property name="MyBigAnsiColumn" type="StringClob" sql-type="VARCHAR(max)" />
バグとして報告しました: https://nhibernate.jira.com/browse/NH-3252
NHibernate(nhusers)フォーラムのユーザーNexusは次のように述べています。
<property name="MyBigAnsiColumn" type="StringClob" sql-type="VARCHAR(max)" />
Should be the most correct answer
注:代わりに、すべてのVARCHAR(MAX)列をNVARCHAR(MAX)に変換することにしたため、これを検証していません。
public class Role
{
public Role() { }
public virtual string RoleId { get; set; }
public virtual string RoleName { get; set; }
public virtual string RoleDescription { get; set; }
}
public class RoleMap : ClassMapping<Role>
{
public RoleMap()
{
Table("nda_roles");
Schema("dbo");
Lazy(true);
Id(x => x.RoleId, map =>
{
map.Column("role_id");
map.Length(12);
map.Type((IIdentifierType)TypeFactory.GetAnsiStringType(12));
map.Generator(Generators.Assigned);
});
Property(x => x.RoleName, map =>
{
map.Column("role_name");
map.NotNullable(true);
map.Length(50);
map.Type(TypeFactory.GetAnsiStringType(50));
});
Property(x => x.RoleDescription, map =>
{
map.Column("role_description");
map.Length(NHibernateConfig.GetMaxLengthAnsiString());
map.Type(TypeFactory.GetAnsiStringType(NHibernateConfig.GetMaxLengthAnsiString()));
});
}
}
public static class NHibernateConfig
{
private static string driver_class;
private static string dialect;
public static ISessionFactory GetNHibernateSessionFactory()
{
var config = new Configuration().Configure(); // Read config from hibernate.cfg.xml
var configPath = HttpContext.Current.Server.MapPath(@"~\hibernate.cfg.xml");
config.Configure(configPath);
driver_class = config.Properties["connection.driver_class"];
dialect = config.Properties["dialect"];
config.CurrentSessionContext<WebSessionContext>();
var mapper = new ModelMapper();
mapper.AddMappings(new Type[]
{
typeof(NDA.Models.RoleMap),
typeof(NDA.Models.PermissionMap),
typeof(NDA.Models.CompanyMap),
typeof(NDA.Models.UserMap),
});
HbmMapping domainMapping = mapper.CompileMappingForAllExplicitlyAddedEntities();
config.AddMapping(domainMapping);
new SchemaExport(config).Execute(false, true, false);
return config.BuildSessionFactory();
}
public static int GetMaxLengthString()
{
int maxlenght = 255;
switch (driver_class)
{
case "NHibernate.Driver.SqlClientDriver":
switch (dialect)
{
case "NHibernate.Dialect.MsSql2008Dialect":
maxlenght = 4000;
break;
}
break;
}
return maxlenght;
}
public static int GetMaxLengthAnsiString()
{
int maxlenght = 255;
switch (driver_class)
{
case "NHibernate.Driver.SqlClientDriver":
switch (dialect)
{
case "NHibernate.Dialect.MsSql2008Dialect":
maxlenght = 8000;
break;
}
break;
}
return maxlenght;
}
}
そしてhibernate.cfg.xmlファイル:
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2" >
<session-factory name="NHibernate.NDA">
<property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
<property name="connection.connection_string_name">nda_connectionstring</property>
<property name="dialect">NHibernate.Dialect.MsSql2008Dialect</property>
<property name="hbm2ddl.auto">validate</property>
<mapping Assembly="NDA"/>