使用Fluent NHibernate将List 映射到分隔的字符串

我的模型看起来像这样:

public class Product { public string Name {get; set;} public string Description {get; set;} public double Price {get; set;} public List Features {get; set;} } 

我希望我的数据库表是平的 – 列表应该存储为分隔字符串:function一|function二|function三例如。

从db中检索时,它应将每个项目放回List中

这可能吗?

我在我当前的项目中做了同样的事情,只是我坚持将枚举的集合作为管道分隔的数字。 它的工作方式相同。

 public class Product { protected string _features; //this is where we'll store the pipe-delimited string public List Features { get { if(string.IsNullOrEmpty(_features) return new List(); return _features.Split(new[]{"|"}, StringSplitOptions.None).ToList(); } set { _features = string.Join("|",value); } } } public class ProductMapping : ClassMap { protected ProductMapping() { Map(x => x.Features).CustomType(typeof(string)).Access.CamelCaseField(Prefix.Underscore); } } 

我为MySql set数据类型实现了类似的东西,它是db中逗号分隔的列表,但是实体模型中的字符串列表。 它涉及在NHibernate中使用基于PrimitiveType类的自定义数据类型。 您可以在地图上使用映射和.CustomType ()方法进行连接。

如果你愿意,我可以为你发送自定义类的代码snipet。

我还为Point3D结构实现了类似的东西。 正如cdmdotnet所说,你基本上想要实现和IUserType,它将通过NullSafeSet / NullSafeGet方法将function打包/解压缩为单个字符串。

您可能还需要实现Equals()方法,这有点微妙。 最好通过一个例子说明原因:

  Product p = session.Load(...); p.Features.Add("extra feature"); session.Save(p); 

问题是,NHibernate on hydration存储对p.Features的引用,并在保存请求时将其与p.Features的值进行比较。 对于不可变属性类型,这很好,但在上面的示例中,这些引用是相同的,因此有效的比较是

 var x = p.Features; var changed = Equals(x, x); 

显然,这个的标准实现总是返回false。

怎么应该处理这个? 我不知道最佳做法是什么,但解决方案是:

  • 使IUserType.Equals(对象x,对象y)始终返回false。 这将强制重建打包字符串,并且每次保存产品时都会进行数据库调用,无论Product是否已在语义上进行了更改。 这是否是一个问题取决于任意数量的因素(Feature对象的大小/数量,未更改时是否保存Product对象,您有多少Product对象等)。

  • 使function成为IList并实现ChangeAwareList : IList ,它能够跟踪更改(或保留其原始副本)。 实现IUserType.Equals(对象x,对象y)以检查x / y是否是ChangeAwareList并实现必要的逻辑以查看列表是否确实已更改。 这是我最终采用的解决方案。

  • 也许你可以重用NHibernate GenericListType类型的代码。 当我实施上一个解决方案时,我没有足够的经验去做这件事。

如果您有NHibernate的一些经验,我希望这可以帮助您入门。 如果不让我知道,我会尝试将更详细的解决方案放在一起。