2011-07-07 75 views
2

我有一個LocalizedString分類用於存儲單個值的本地化。該概念鬆散地基於post by Fabio Maulo。我在NHibernate 3.2中使用了新的Mapping-By-Code概念,但它似乎忽略了IUserType的實現,因爲當它生成SQL時,它會創建一個具有不同名稱的列和默認字符串NVARCHAR(255)類型。NHibernate 3.2映射的代碼忽略我的IUserType

我試圖映射這個簡單的類

public class Region : Entity 
{ 
    /// <summary> 
    /// Initializes a new instance of the <see cref="Region"/> class. 
    /// </summary> 
    public Region() 
    { 
    } 

    /// <summary> 
    /// Gets or sets the localized name of the <see cref="Region"/>. 
    /// </summary> 
    public virtual LocalizedString Name { get; set; } 
} 

產生的SQL是

create table Regions (RegionId INT not null, Item NVARCHAR(255) not null, primary key (RegionId)) 

這裏的Item列應該叫Name,它應該是XML類型的。我認爲列名來自LocalizedString的索引器的名稱。

這是我的NHibernate的配置(它不是完整的,我是在建設公約的過程)

private static Configuration CreateNHibernateConfiguration() 
{ 
    var cfg = new Configuration(); 
    cfg.Proxy(p => p.ProxyFactoryFactory<NHibernate.Bytecode.DefaultProxyFactoryFactory>()) 
     .DataBaseIntegration(db => 
     { 
      db.ConnectionStringName = "***"; 
      db.Dialect<MsSql2008Dialect>(); 
      db.BatchSize = 500; 
     }); 

    var mapper = new ConventionModelMapper(); 
    var baseEntityType = typeof(Entity); 
    mapper.IsEntity((t, declared) => baseEntityType.IsAssignableFrom(t) && baseEntityType != t && !t.IsInterface); 
    mapper.IsRootEntity((t, declared) => baseEntityType.Equals(t.BaseType)); 

    mapper.BeforeMapClass += (mi, t, map) => 
      { 
       map.Table(Inflector.MakePlural(t.Name)); 
       map.Id(x => 
        { 
         x.Column(t.Name + "Id"); 
        }); 
      }; 

    mapper.BeforeMapManyToOne += (insp, prop, map) => 
      { 
       map.Column(prop.LocalMember.GetPropertyOrFieldType().Name + "Id"); 
       map.Cascade(Cascade.Persist); 
      }; 

    mapper.BeforeMapBag += (insp, prop, map) => 
      { 
       map.Key(km => km.Column(prop.GetContainerEntity(insp).Name + "Id")); 
       map.Cascade(Cascade.All); 
      }; 

    mapper.BeforeMapProperty += (insp, prop, map) => 
      { 
       map.NotNullable(true); 
      }; 

    var exportedTypes = baseEntityType.Assembly.GetExportedTypes(); 
    mapper.AddMappings(exportedTypes.Where(t => t.Namespace.EndsWith("Mappings", StringComparison.Ordinal))); 

    var mapping = mapper.CompileMappingFor(exportedTypes.Where(t => t.Namespace.EndsWith("Data", StringComparison.Ordinal))); 

    cfg.AddDeserializedMapping(mapping, "MyModel"); 
    SchemaMetadataUpdater.QuoteTableAndColumns(cfg); 

    return cfg; 
} 

這是IUserType定義我LocalizedString類:

/// <summary> 
/// Defines a string that can have a different value in multiple cultures. 
/// </summary> 
public sealed partial class LocalizedString : IUserType 
{ 
    object IUserType.Assemble(object cached, object owner) 
    { 
     var value = cached as string; 
     if (value != null) 
     { 
      return LocalizedString.Parse(value); 
     } 

     return null; 
    } 

    object IUserType.DeepCopy(object value) 
    { 
     var toCopy = value as LocalizedString; 
     if (toCopy == null) 
     { 
      return null; 
     } 

     var localizedString = new LocalizedString(); 
     foreach (var localizedValue in toCopy.localizedValues) 
     { 
      localizedString.localizedValues.Add(localizedValue.Key, localizedValue.Value); 
     } 

     return localizedString; 
    } 

    object IUserType.Disassemble(object value) 
    { 
     var localizedString = value as LocalizedString; 
     if (localizedString != null) 
     { 
      return localizedString.ToXml(); 
     } 

     return null; 
    } 

    bool IUserType.Equals(object x, object y) 
    { 
     if (x == null && y == null) 
     { 
      return true; 
     } 

     if (x == null || y == null) 
     { 
      return false; 
     } 

     var localizedStringX = (LocalizedString)x; 
     var localizedStringY = (LocalizedString)y; 

     if (localizedStringX.localizedValues.Count() != localizedStringY.localizedValues.Count()) 
     { 
      return false; 
     } 

     foreach (var value in localizedStringX.localizedValues) 
     { 
      if (!localizedStringY.localizedValues.ContainsKey(value.Key) || localizedStringY.localizedValues[value.Key] == value.Value) 
      { 
       return false; 
      } 
     } 

     return true; 
    } 

    int IUserType.GetHashCode(object x) 
    { 
     if (x == null) 
     { 
      throw new ArgumentNullException("x"); 
     } 

     return x.GetHashCode(); 
    } 

    bool IUserType.IsMutable 
    { 
     get { return true; } 
    } 

    object IUserType.NullSafeGet(System.Data.IDataReader rs, string[] names, object owner) 
    { 
     if (rs == null) 
     { 
      throw new ArgumentNullException("rs"); 
     } 

     if (names == null) 
     { 
      throw new ArgumentNullException("names"); 
     } 

     if (names.Length != 1) 
     { 
      throw new InvalidOperationException("names array has more than one element. can't handle this!"); 
     } 

     var val = rs[names[0]] as string; 

     if (val != null) 
     { 
      return LocalizedString.Parse(val); 
     } 

     return null; 
    } 

    void IUserType.NullSafeSet(System.Data.IDbCommand cmd, object value, int index) 
    { 
     if (cmd == null) 
     { 
      throw new ArgumentNullException("cmd"); 
     } 

     var parameter = (DbParameter)cmd.Parameters[index]; 

     var localizedString = value as LocalizedString; 
     if (localizedString == null) 
     { 
      parameter.Value = DBNull.Value; 
     } 
     else 
     { 
      parameter.Value = localizedString.ToXml(); 
     } 
    } 

    object IUserType.Replace(object original, object target, object owner) 
    { 
     throw new NotImplementedException(); 
    } 

    Type IUserType.ReturnedType 
    { 
     get { return typeof(LocalizedString); } 
    } 

    NHibernate.SqlTypes.SqlType[] IUserType.SqlTypes 
    { 
     get { return new[] { new XmlSqlType() }; } 
    } 
} 

回答

6

你不應在域模型中使用IUserType。

IUserType接口實際上應該叫做IUserTypeMapper,你必須在映射中明確指定它。

我建議你重新閱讀那篇文章。


更新:試試這個按照慣例到您的類型映射:

mapper.BeforeMapProperty += 
    (insp, prop, map) => 
    { 
     if (/*determine if this is member should be mapped as LocalizedString*/) 
      map.Type<LocalizedString>(); 
    }; 

當然的「確定......」部分將是一些你確定,如屬性名開頭「本地化」,自定義屬性或任何你想要的。

+1

好吧,我喜歡不把它綁定到我的域模型的概念。你知道如何通過代碼約定通過新的NHibernate 3.2自動將域模型對象映射到他們的IUserType映射器嗎? –

+0

@ Pierre-AlainVigeant:發佈您的配置代碼而不是用戶類型,我會嘗試查看它可以添加的位置。 –

+0

我更新了問題以包含我的NH配置 –

相關問題