2012-08-24 120 views
13

我們有VARCHAR和nvarchar最大列的SQL Server表這樣的映射VARCHAR(MAX)列:如何NHibernate的的hbm.xml映射文件

CREATE TABLE [dbo].[MyTable](
    : 
    [MyBigUnicodeColumn] [nvarchar](max) NULL, 
    [MyBigAnsiColumn] [varchar](max) NULL, 
    : 

在創建映射(的hbm.xml)文件中,documentation表示使用StringClob作爲數據庫類型爲DbType.String的大對象的類型屬性,但它沒有說明如果數據庫類型爲DbType.AnsiString該怎麼辦。

<class name="MyTable" table="MyTable" lazy="false"> 
    : 
    <property name="MyBigUnicodeColumn" type="StringClob" /> 
    <property name="MyBigAnsiColumn" type="????" /> 
    : 

這是爲NHibernate 3.3.1。

回答

20

您可以將它們映射爲stringAnsiString。如果長度分別大於4000或8000,則NH創建nvarchar(max)或varchar(max)。

我可能認爲這個長度是用於sql參數的,並且它被截斷到指定的長度(這取決於你使用的NH版本,有一些變化)。所以最好指定它足夠大。


編輯:不幸的是,它不與AnsiString類型相同,與正常字符串的工作。我讀了一些NH代碼,發現如下:

varchar(max)由SQL Server 2005的方言支持。

MsSql2000Dialect.cs,線205

RegisterColumnType(DbType.AnsiString, SqlClientDriver.MaxSizeForLengthLimitedAnsiString, "VARCHAR($l)"); 

MsSql2005Dialect.cs 19行:

RegisterColumnType(DbType.AnsiString, SqlClientDriver.MaxSizeForAnsiClob, "VARCHAR(MAX)"); 

它註冊的varchar(最大值)作爲SQL類型來選擇當AnsiString類型被映射較大然後8000.

在SqlClientDriver.cs中,您可以看到它在字符串的參數中實現了「blob」,但不是用於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; 

它始終將8000作爲AnsiString類型參數的限制。

由於驅動程序和方言之間的不一致,我會稱之爲錯誤。

因爲所有的AnsiStrings都會發生這個錯誤,所以在映射中指定sql-type(NH能夠選擇正確的sql類型)並沒有幫助。您需要使用在thread you started on the NH forum提出的解決方法:

<property name="MyBigAnsiColumn" type="StringClob" sql-type="VARCHAR(max)" /> 

我報告說,它作爲一個bug:https://nhibernate.jira.com/browse/NH-3252

+0

AnsiString類型被定義爲非Unicode字符串,所以這不應該被打破。我想這隻會改變,如果未來的SQL Server將提供新的方式來存儲字符串或ANSI字符串在指定的長度。 –

+0

另一方面,這一切都在方言中實現,並且很容易擁有自己的方言。 –

+0

這取決於您使用的NH版本。它們在傳遞參數時指定了長度,以便使SQL Server重用查詢。用於切斷數據的SQL Server客戶端非常糟糕,因此請檢查其長度。如果你想使用2GB的最大長度的洞,可以像這樣指定它...... –

0

用戶的Nexus在NHibernate的(nhusers)論壇上表示:

<property name="MyBigAnsiColumn" type="StringClob" sql-type="VARCHAR(max)" /> 
Should be the most correct answer 

注意:我沒有驗證過這一點,因爲我決定將所有VARCHAR(MAX)列轉換爲NVARCHAR(MAX)。

1
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"/>