我的模型看起来像这样:
public class Product
{
public string Name {get; set;}
public string Description {get; set;}
public double Price {get; set;}
public List<string> Features {get; set;}
}
我希望我的数据库表是平的 - List应该存储为分隔的字符串: 功能一|功能二|功能三例如。
从数据库中检索时,应将每个项目放回List
这可能吗?
答案 0 :(得分:11)
我在我当前的项目中做的一样,只是我将枚举的集合作为管道分隔的数字。它的工作方式相同。
public class Product
{
protected string _features; //this is where we'll store the pipe-delimited string
public List<string> Features {
get
{
if(string.IsNullOrEmpty(_features)
return new List<String>();
return _features.Split(new[]{"|"}, StringSplitOptions.None).ToList();
}
set
{
_features = string.Join("|",value);
}
}
}
public class ProductMapping : ClassMap<Product>
{
protected ProductMapping()
{
Map(x => x.Features).CustomType(typeof(string)).Access.CamelCaseField(Prefix.Underscore);
}
}
答案 1 :(得分:0)
我为MySql set数据类型实现了类似的东西,它是db中逗号分隔的列表,但是实体模型中的字符串列表。它涉及在NHibernate中使用基于PrimitiveType类的自定义数据类型。你使用映射和.CustomType&lt;来连接它。地图上的CustomType&gt;()方法。
如果您愿意,我可以向您发送自定义类的代码snipet。
答案 2 :(得分:0)
我还为Point3D结构实现了类似的功能。正如cdmdotnet所说,你基本上想要实现和IUserType,它将通过NullSafeSet / NullSafeGet方法将功能打包/解包为单个字符串。
您可能还需要实现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对象等)。
使功能成为IList并实现ChangeAwareList<T> : IList<T>
能够跟踪更改(或保留其原始副本)的功能。实现IUserType.Equals(对象x,对象y)以检查x / y是否是ChangeAwareList并实现必要的逻辑以查看列表是否确实已更改。这是我最终采用的解决方案。
也许你可以重用NHibernate GenericListType类型的代码。当我实施上一个解决方案时,我没有足够的经验去做这件事。
如果您有NHibernate的一些经验,我希望这可以帮助您入门。如果不让我知道,我会尝试将更详细的解决方案放在一起。