2016-08-02 119 views
0

我有一个数据库,它保存一个项目的Id,该项目存储在另一个系统中并反序列化为代码中的对象。我正在尝试使用Fluent NHibernate来构建由来自数据库和外部服务的数据组成的域模型实体。一个例子会更好地解释这一点。在数据库中我有一张如下所示的表:在Fluent NHibernate中映射一个自定义类型属性

CREATE TABLE entities 
(
    id integer NOT NULL, 
    custom_thing text NOT NULL, 
    CONSTRAINT entities_id_pk PRIMARY KEY (id) 
); 

这是PostgreSQL,但问题不是数据库特定的。现在,在代码中,我有这些类:

class Entity 
{ 
    public virtual int Id { get; set; } 

    public virtual CustomThing CustomThing { get; set; } 
} 

class CustomThing 
{ 
    public string Id { get; set; } 
    public string Name { get; set; } 
} 

我试图用一个CustomMap定义映射:

class EntityMap : ClassMap<Entity> 
{ 
    public EntityMap() 
    { 
     Table("entities"); 
     Id(e => e.Id, "id").GeneratedBy.Assigned(); 
     // Map(e => e.CustomThing, "custom_thing"); 
    } 
} 

的问题是:我怎么能映射CustomThing?下面是一个试图映射Entity类的程序(如果在PostgreSQL数据库上运行,需要FluentNHibernate包和NpgSQL)。为简单起见我只在代码创建的CustomThing实例:

class Program 
{ 
    // How to use this in mapping? 
    static CustomThing[] _customThings = 
    { 
     new CustomThing {Id = "abc", Name = "ABC"}, 
     new CustomThing {Id = "def", Name = "DEF"} 
    }; 

    static void Main() 
    { 
     using (ISessionFactory sessionFactory = Fluently.Configure() 
      .Database(PostgreSQLConfiguration.Standard 
       .ConnectionString(
        @"Server=localhost; Database=test_nhibernate; User Id=postgres; Password=little_secret;")) 
      .Mappings(m => m.FluentMappings.AddFromAssemblyOf<Entity>()) 
      .BuildSessionFactory()) 
     { 
      using (ISession session = sessionFactory.OpenSession()) 
      { 
       var entity = session.Get<Entity>(1); 

       Console.WriteLine($"{entity?.Id} {entity?.CustomThing?.Name}"); 
      } 
     } 
     Console.ReadLine(); 
    } 
} 

的输出当然仅Id属性值的,因为CustomThing映射没有定义。是否可以配置映射,以便我可以将参数传递给它,并以某种方式通过Id属性将custom_thing列值映射到_customThings中的对象?

+0

我解决了同样的问题与此存储属性作为JSON文本和创建新的自定义“用户类型”序列化和反序列化对象,如果这个解决方案是适合你的,我可以为你提供一些代码片段? – mdameer

+0

@mdameer谢谢,好吧,我想我明白了这一点,但你是如何指示映射器分配该JSON的?我假设你的意思是'Entity.CustomThing'在这里是'string'类型。问题是,在'实体'表中,我不存储整个序列化的CustomThing,而只存储它的Id。其他属性来自外部服务,它具有完整的CustomThing JSON结构。您的解决方案在这种情况下会工作吗 – Caleb9

回答

3

是的,您可以通过保存Id,并获取代码中的其余数据,或者将您的映射器中的所有东西都返回给您,如果您选择第二个选项,您可以按照此代码:

[Serializable] 
public class CustomThingUserType : IUserType { 
    public new bool Equals(object x, object y) { 
     if (object.ReferenceEquals(x, y)) 
      return true; 

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

     return x.Equals(y); 
    } 

    public int GetHashCode(object x) { 
     if (x == null) 
      return 0; 

     return x.GetHashCode(); 
    } 

    public object NullSafeGet(IDataReader rs, string[] names, object owner) { 
     if (names.Length == 0) 
      throw new ArgumentException("Expecting at least one column"); 

     int id = (int)NHibernateUtil.Int32.NullSafeGet(rs, names[0]); 

     var obj = new CustomThing { Id = id }; 

     // here you can grab your data from external service 

     return obj; 
    } 

    public void NullSafeSet(IDbCommand cmd, object value, int index) { 
     var parameter = (DbParameter)cmd.Parameters[index]; 

     if (value == null) { 
      parameter.Value = 0; 
     } 
     else { 
      parameter.Value = ((CustomThing)value).Id; 
     } 
    } 

    public object DeepCopy(object value) { 
     return value; 
    } 

    public object Replace(object original, object target, object owner) { 
     return original; 
    } 

    public object Assemble(object cached, object owner) { 
     return cached; 
    } 

    public object Disassemble(object value) { 
     return value; 
    } 

    public SqlType[] SqlTypes { 
     get { 
      return new SqlType[] { new SqlType(DbType.Int32) }; 
     } 
    } 

    public Type ReturnedType { 
     get { return typeof(CustomThing); } 
    } 

    public bool IsMutable { 
     get { return false; } 
    } 
} 
+0

第二个选项确实有效。为了完整性,我将补充说现在'EntityMap'中的映射现在应该是这样的:'Map(e => e.CustomThing,“custom_thing”)。CustomType ();'。我还必须将'id'类型更改为字符串以适合我的示例。谢谢! :) – Caleb9

相关问题