2012-08-24 5 views
13

Abbiamo una tabella SQL Server con le colonne max varchar e nvarchar come questo:Come mappare una colonna VARCHAR (MAX) in NHibernate hbm.xml file di mapping

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

Quando si crea la mappatura (hbm.xml) file, il documentation dice di usare StringClob come attributo type per oggetti di grandi dimensioni con un tipo di database di DbType.String, ma non dice cosa fare se il tipo di database è DbType.AnsiString.

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

Questo è per NHibernate 3.3.1.

risposta

20

È possibile mapparli come string o AnsiString.

<property name="MyBigUnicodeColumn" type="string" length="1000000"/> 
<property name="MyBigAnsiColumn" type="AnsiString" length="1000000" /> 

Ogni volta che la lunghezza è più grande quindi 4000 o 8000, rispettivamente, NH crea un nvarchar (max) o varchar (max).

È possibile che la lunghezza sia utilizzata per i parametri sql e che sia troncata alla lunghezza specificata (dipende dalla versione NH in uso, alcune modifiche sono state apportate). Quindi meglio specificarlo abbastanza grande.


Edit: Purtroppo, non funziona con la AnsiString lo stesso con stringhe normali. Ho letto alcuni codici NH e ho trovato quanto segue:

varchar (max) è supportato dal dialetto da SQL Server 2005 in poi.

MsSql2000Dialect.cs, linea 205

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

MsSql2005Dialect.cs, linea 19:

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

Registra varchar (max) come il tipo SQL di scegliere quando un AnsiString viene mappato grande poi 8000.

In SqlClientDriver.cs è possibile vedere che implementa "blob" nei parametri per le stringhe, ma non per le stringhe ansi (riga 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; 

Imposta sempre 8000 come limite del parametro di tipo AnsiString.

A causa dell'incongruenza tra il driver e il dialetto, lo chiamerei un bug.

Poiché l'errore si verifica su tutte le AnsiStrings, non aiuta a specificare il tipo sql nel mapping (NH è in grado di scegliere il tipo sql corretto).È necessario utilizzare la soluzione proposta nel thread you started on the NH forum:

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

ho segnalato come un bug: https://nhibernate.jira.com/browse/NH-3252

+0

AnsiString è per definizione una stringa non Unicode, quindi questo non dovrebbe essere rotto. Penso che questo cambierebbe solo se i futuri SQL Server offrissero nuovi modi per memorizzare una stringa o una stringa ansi nella lunghezza specificata. –

+0

Dall'altro lato, tutto questo è implementato nel Dialetto, ed è abbastanza facile avere il proprio dialetto. –

+0

Dipende dalla versione NH in uso. Specificano la lunghezza durante il passaggio dei parametri, in modo che SQL Server riutilizzi le query. Il client SQL Server utilizzato per tagliare i dati, che era molto cattivo, quindi il controllo della lunghezza. Se vuoi usare il foro di 2 GB di lunghezza massima, specificalo in questo modo ... –

0

utente Nexus sul forum NHibernate (nhusers) ha detto:

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

Nota: non ho verificato questo perché ho deciso di convertire tutte le colonne VARCHAR (MAX) in 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; 
    } 

} 

E hibernate.cfg.xml di file:

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