29

如何使用 Entity Framework Code-First 将双精度数组存储到数据库,而不影响现有代码和架构设计?

我查看了 Data Annotation 和 Fluent API,我还考虑将双精度数组转换为字节字符串并将该字节存储到数据库中它自己的列中。

我无法public double[] Data { get; set; }使用 Fluent API 访问该属性,然后我得到的错误消息是:

该类型double[]必须是不可为空的值类型才能将其用作参数“T”。

存储的类Data成功存储在数据库中,以及与该类的关系。我只是错过了Data专栏。

4

9 回答 9

50

你可以做这样的事情:

    [NotMapped]
    public double[] Data
    {
        get
        {
            string[] tab = this.InternalData.Split(',');
            return new double[] { double.Parse(tab[0]), double.Parse(tab[1]) };
        }
        set
        {
            this.InternalData = string.Format("{0},{1}", value[0], value[1]);
        }
    }

    [EditorBrowsable(EditorBrowsableState.Never)]
    public string InternalData { get; set; }
于 2013-03-05T10:07:25.350 回答
30

感谢大家的投入,由于您的帮助,我能够找到解决此问题的最佳方法。这是:

 public string InternalData { get; set; }
 public double[] Data
 {
    get
    {
        return Array.ConvertAll(InternalData.Split(';'), Double.Parse);                
    }
    set
    {
        _data = value;
        InternalData = String.Join(";", _data.Select(p => p.ToString()).ToArray());
    }
 }

感谢这些 stackoverflow 帖子: String to Doubles arrayArray of Doubles to a String

于 2013-03-05T12:07:23.143 回答
5

我知道它有点贵,但你可以这样做

class Primitive
{
    public int PrimitiveId { get; set; }
    public double Data { get; set; }

    [Required]
    public Reference ReferenceClass { get; set; }
}

// This is the class that requires an array of doubles
class Reference
{
    // Other EF stuff

    // EF-acceptable reference to an 'array' of doubles
    public virtual List<Primitive> Data { get; set; }
}

现在,这会将单个实体(此处为“参考”)映射到您的 Primitive 类的“列表”。这基本上是为了让 SQL 数据库满意,并允许您适当地使用您的数据列表。

这可能不适合您的需求,但会是让 EF 满意的一种方式。

于 2013-03-05T10:42:38.677 回答
4

List<double>如果你使用而不是,那会容易得多double[]。您已经有一个存储您的Data值的表。您可能有从某个表到存储双精度值的表的外键。创建另一个模型来反映存储双精度的表,并在映射类中添加外键映射。这样您就不需要添加一些复杂的后台逻辑来检索或存储类属性中的值。

于 2013-03-05T11:05:31.957 回答
2

Nathan White 给出了最好的答案(得到了我的投票)。

这是对 Joffrey Kern 的回答的一个小改进,允许任何长度的列表(未经测试):

    [NotMapped]
    public IEnumerable<double> Data
    {
        get
        {
            var tab = InternalData.Split(',');
            return tab.Select(double.Parse).AsEnumerable();
        }
        set { InternalData = string.Join(",", value); }
    }

    [EditorBrowsable(EditorBrowsableState.Never)]
    public string InternalData { get; set; }
于 2017-08-01T16:25:30.430 回答
1

不要使用 double[] 使用 List insted。

像这样。

public class MyModel{
    ...
    public List<MyClass> Data { get; set; }
    ...
}

public class MyClass{
    public int Id { get; set; }
    public double Value { get; set; }
}

我看到的所有解决方案都很糟糕,因为:

  1. 如果你创建表,你不想存储这样的数据:“99.5,89.65,78.5,15.5”那是无效的!首先它是一个字符串,这意味着如果您可以在其中输入字母,并且在您的 ASP.NET 服务器调用 double.Parse 的那一刻,它将导致 FormatException 并且您真的不想要!

  2. 它更慢,因为您的服务器必须解析字符串。为什么要解析字符串而不是从 SQL Server 获取几乎准备好的数据以供使用?

于 2018-05-21T19:55:10.267 回答
1

如果您的收藏可以是null或空的,并且您希望保留它,请执行以下操作:

[NotMapped]
public double[] Data
{
    get => InternalData != null ? Array.ConvertAll(Data.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries), double.Parse) : null;
    set => InternalData = value != null ? string.Join(";", value) : null;
}

此外,[Column(TypeName = "varchar")]在字符串属性上指定更有效的存储数据类型。

于 2021-01-08T15:36:22.110 回答
0

@Jonas答案的完美增强将是添加必要的注释。所以,一个更干净的版本将是

[EditorBrowsable(EditorBrowsableState.Never)]
[JsonIgnore]
public string InternalData { get; set; }

[NotMapped]
public double[] Data
{
    get => Array.ConvertAll(InternalData.Split(';'), double.Parse);
    set 
    {
        InternalData = string.Join(";", value.Select(p => p.ToString(CultureInfo.InvariantCulture)).ToArray());
    }
}

[ JsonIgnore]注解将忽略 JSON 序列化和 Swagger UI 中的 InternalData 字段。

[EditorBrowsable(EditorBrowsableState.Never)]将从 IDE IntelliSense 隐藏公共方法

于 2021-04-14T22:54:07.067 回答
0

在我看来,几乎所有其他答案都与应有的相反。实体 EF 应该管理字符串,并且必须从中生成数组。因此,只有当 EF 访问该字符串时,该数组必须是整体读写的。

涉及 Data[] 逻辑的解决方案是错误的,因为正如我在评论中所写,您会遇到矛盾的情况。在所有其他条件下,变量必须保持为纯数组。正如我目前所见,通过将“get”和“set”逻辑放入 Data[] 中,会发生这种情况:

1 - 每次对数组进行索引访问时,都会自动从字符串重新创建数组。这是一个无用的工作,想想循环中的迭代......

2 - 当您设置单个元素时,它不会被存储,因为它通过“get”而不是“set”。如果您尝试声明Data=new []{0,0,0}然后设置Data[1]=2,则重新读取 Data[1] 结果为 0。

我的解决方案是彻底扭转逻辑。

    public string Data_string
    {
        get => string.Join(';', Data??Array.Empty());
        set => Data= value == null ? Array.Empty<double>() : Array.ConvertAll(value.Split(';',StringSplitOptions.RemoveEmptyEntries), double.Parse);
    }
   
    [NotMapped]
    public double[] Data {get;set;}
   

显然,这只适用于在数据库上存储和检索数据,对 Data_string 的访问是 EF 独有的。

一旦从 DB 中读取字符串,它就会与Data_string相关联,后者通过 set 创建Data数组。此时,您可以处理Data 而不会以任何方式影响字符串,例如普通数组。当您要求 EF 保存到 DB 中时,通过Data_string属性中的 get,字符串将根据Data元素完全重构,然后存储为字符串。

实际上,字符串只修改了两次,在从数据库读取时和保存时。

在我看来,这个解决方案比在字符串上连续运行要高效得多。

于 2021-12-15T15:55:42.840 回答