映射列表使用 Fluent NHibernate 转换为分隔字符串

发布于 2024-10-02 19:47:05 字数 331 浏览 2 评论 0原文

我的模型看起来像这样:

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

我希望我的数据库表是平坦的 - 列表应该存储为分隔字符串: 以特征一|特征二|特征三为例。

从数据库检索时,它应该将每个项目放回列表中

这可能吗?

My model looks something like this:

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

I want my database table to be flat - the List should be stored as a delimited string:
Feature one|Feature two|Feature three for example.

When retrieved from the db, it should place each of those items back into a List

Is this possible?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

最美的太阳 2024-10-09 19:47:05

我在当前的项目中做了同样的事情,只是我将枚举集合保留为管道分隔的数字。它的工作原理是一样的。

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);
    }
}

I'm doing the very same in my current project, only I'm persisting a collection of enums as pipe-delimited numbers. It works the same way.

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);
    }
}
好听的两个字的网名 2024-10-09 19:47:05

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

如果您愿意,我可以向您发送自定义类的代码片段。

I implemented something similar for the MySql set data type, which is a comma separated list in the db but a list of strings in the entity model. It involved using a custom data type in NHibernate, based on the PrimitiveType class. You wire this in using the mappings and the .CustomType< CustomType >( ) method on a map.

If you want I can send you a code snipet for the custom class.

过去的过去 2024-10-09 19:47:05

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

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

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

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

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

显然,此标准实现将始终返回 false。

应该如何处理这个问题呢?我不知道最佳实践是什么,但解决方案是:

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

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

  • 也许您可以重用 NHibernate GenericListType 类型的代码。当我实现以前的解决方案时,我没有足够的经验来尝试这个。

如果您之前有一些 NHibernate 经验,我希望这可以帮助您入门。如果没有让我知道,我会尝试制定一个更详细的解决方案。

I also implemented something similar for a Point3D struct. As cdmdotnet said you basically want to implement and IUserType that will pack/unpack Features into a single string via the NullSafeSet/NullSafeGet methods.

You may also need to implement the Equals() method, which is a little subtle. The reason why is best illustrated by an example:

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

The thing is, NHibernate upon hydration stores a reference to p.Features, and compares it to the value of p.Features upon a save request. For immutable property types this is fine, but in the above example, these references are identical, so the effective comparison is

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

Obviously a standard implementation of this will always return false.

How should one deal with this? I have no idea what the best practice is, but solutions are:

  • Make IUserType.Equals(object x, object y) always return false. This will force the packed string to be rebuilt and a database call to be made every single time the Product is saved, irregardless of whether Product has been semantically changed or not. Whether or not this is an issue depends on any number of factors (size/count of Feature objects, whether Product objects are saved when not changed, how many Product objects you have etc).

  • Make Features an IList and implement a ChangeAwareList<T> : IList<T> which is able to track changes (or keep a copy of its original) aware. Implement IUserType.Equals(object x, object y) to check if x/y are ChangeAwareList and implement the necessary logic to see if the list really has changed. This is the solution I went with in the end.

  • Maybe you could reuse code from the NHibernate GenericListType type. At the time I implemented the previous solution I didn't have enough experience to have a go at this.

If you have some prior experience with NHibernate I hope this should help get you started. If not let me know and I will try and put together a more verbose solution.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文