【问题标题】:Storing C# data structure into a SQL database将 C# 数据结构存储到 SQL 数据库中
【发布时间】:2008-10-19 23:54:10
【问题描述】:

我是 ASP.NET 和 SQL 服务器领域的新手,所以请原谅我的无知...

如果我在 C# 中有一个数据结构(例如,我们只是说一个存储一些字符串的向量),是否可以将向量的内容按原样存储在 SQL 表中?我想这样做,以便尽可能快地将数据转换回矢量形式,而不必逐个元素地构造它。几乎就像将二进制数据写入文件,然后读取它并将其复制到 C 中分配的结构中。

我在 SQL Server 2008 上创建了一个表,其字段定义为 VARBINARY(MAX)。我想我会从那个开始。

有人可以向我展示一个示例,说明我将如何在该字段中存储和检索一个由 10 个字符串组成的向量,并从该字段中检索出一个向量?这甚至可能吗(我想不出为什么不)?

谢谢!

【问题讨论】:

    标签: c# asp.net sql data-structures


    【解决方案1】:

    首先,显而易见的方法是创建一个关系结构并将对象映射到数据库中的字段。

    其次,如果你有一个可序列化的对象,你可以将它存储在 SQL Server 中。我有时会这样做,并使用 SQL Server 中的 Text 数据类型来存储 XML。

    意见:我更喜欢将序列化对象存储为 XML 而不是二进制数据。 为什么?因为您实际上可以读取其中的内容(用于调试),并且在 SQL Server 中您可以使用 XQuery 从序列化对象中选择数据。根据我的经验,与使用更易于调试且可以以伪关系方式使用的数据相比,使用二进制数据的性能提升并不值得。看看SQL Server's XQuery capabilities。即使您不打算立即使用它,也没有理由让自己陷入困境。

    您可以查看一些使用NetDataContractSerializer 的示例。

    我相信你所说的向量是 C# 中的 List。查看 System.Collections.Generic。您可以使用 NetDataContractSerializer 序列化 3 个字符串的列表,例如:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Runtime.Serialization;
    using System.IO;
    
    namespace SerializeThingy
    {
        class Program
        {
            static void Main(string[] args)
            {
                List<string> myList = new List<string>();
                myList.Add("One");
                myList.Add("Two");
                myList.Add("Three");
                NetDataContractSerializer serializer = new NetDataContractSerializer();
                MemoryStream stream = new MemoryStream();
                serializer.Serialize(stream, myList);
                stream.Position = 0;
                Console.WriteLine(ASCIIEncoding.ASCII.GetString(stream.ToArray()));
                List<string> myList2 = (List<string>)serializer.Deserialize(stream);
                Console.WriteLine(myList2[0]);
                Console.ReadKey();
            }
        }
    }
    

    这个例子只是序列化一个列表,将序列化输出到控制台,然后在另一面证明它是正确的。我认为您可以从这里看到,您可以将内存流转储为字符串并将其写入数据库,或者使用其他流类型而不是内存流来执行此操作。

    记得参考 System.Runtime.Serialization 以访问 NetDataContractSerializer。

    【讨论】:

    • @Jason Jackson 我同意你的观点,当你说“我更喜欢将序列化对象存储为 XML 而不是二进制数据”,但是如果我必须序列化接口怎么办?
    • 接口不可序列化,因此必须忽略已实现的属性...在某些情况下,如果您对数据结构的创建进行耗时操作,上述方法非常有用...我更喜欢以这种方式使用 JSON 序列化程序你会节省内存...
    • 在过去的几年里,我在 XML 和 JSON 上一蹶不振。我目前的工作有一些非常独特的数据存储要求,需要做很多规范化的数据结构,还有很多一次性的,我们通常将它们作为 JSON 存储在 nvarchar(max) 列中。最近,出于性能和其他原因,我们已经从 NHibernate 转移到 Dapper,并且一直在做很多更多纯 SQL,我发现 XML 帮助了我几次,因为 T-SQL内置用于查询的 XML。我认为如果过度使用它会变得危险,但它很有用。
    【解决方案2】:
    [Serializable]
    public struct Vector3
    {
        public double x, y, z;
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            Vector3 vector = new Vector3();
            vector.x = 1;
            vector.y = 2;
            vector.z = 3;
    
            MemoryStream memoryStream = new MemoryStream();
            BinaryFormatter binaryFormatter = new BinaryFormatter();
            binaryFormatter.Serialize(memoryStream, vector);
            string str = System.Convert.ToBase64String(memoryStream.ToArray());
    
            //Store str into the database
        }
    }
    

    【讨论】:

    • 为什么要转换成字符串?他的专栏是二进制的。
    • 如果他来自 C,那么一个向量可能意味着一个列表:en.wikipedia.org/wiki/Std::vector
    【解决方案3】:

    假设对象标有[Serializable] 或实现ISerializable,BinaryFormatter 类提供了一个简单的方法来做到这一点。

    如果没有,您正在查看(非平凡的)自定义代码。

    【讨论】:

      【解决方案4】:

      如果您要这样做(我想这在技术上是可能),您不妨使用平面文件:不再使用关系数据库。

      【讨论】:

      • 所以你的意思是如果你需要持久化一些不是内置数据库列类型的东西,你应该改用平面文件?
      • 为什么不使用数据库?它当然具有比平面文件更具可扩展性的优势。如果您使用 XML 序列化格式,您还可以使用 XQuery 查询 SQL Server 中的数据。
      • 如果您将复杂对象持久化到数据库中,则对象中的每个字段都应该有自己的列或表,以便您可以在该字段上进行搜索和查询。
      • 我同意在绝大多数情况下使用关系结构是有意义的。当您拥有基于可自定义模板的数据时,此操作会失败。如果您不知道在设计时将存在哪些字段,则很难在数据库中提出规范化的数据结构。
      • 除非您绝对需要查询它,否则在关系数据库中重新创建对象的结构是没有意义的。即便如此,如果您将对象作为 xpath-queryable xml 放入,则支持起来会更加简单和容易。
      【解决方案5】:

      这是通用列表的另一种更通用的方法。注意,存储在列表中的实际类型也必须是可序列化的

      using System.Runtime.Serialization.Formatters.Binary;
      using System.IO;
      using System.Data.SqlClient;
      using System.Runtime.Serialization;
      
      public byte[] SerializeList<T>(List<T> list)
      {
      
          MemoryStream ms = new MemoryStream();
      
          BinaryFormatter bf = new BinaryFormatter();
      
          bf.Serialize(ms, list);
      
          ms.Position = 0;
      
          byte[] serializedList = new byte[ms.Length];
      
          ms.Read(serializedList, 0, (int)ms.Length);
      
          ms.Close();
      
          return serializedList; 
      
      } 
      
      public List<T> DeserializeList<T>(byte[] data)
      {
          try
          {
              MemoryStream ms = new MemoryStream();
      
              ms.Write(data, 0, data.Length);
      
              ms.Position = 0;
      
              BinaryFormatter bf = new BinaryFormatter();
      
              List<T> list = bf.Deserialize(ms) as List<T>;
      
              return list;
          }
          catch (SerializationException ex)
          {
              // Handle deserialization problems here.
              Debug.WriteLine(ex.ToString());
      
              return null;
          }
      
      }
      

      然后在客户端代码中:

      List<string> stringList = new List<string>() { "January", "February", "March" };
      
      byte[] data = SerializeList<string>(stringList);
      

      存储/检索此字节数组的一种基本方法是使用简单的 SQLClient 对象:

      SqlParameter param = new SqlParameter("columnName", SqlDbType.Binary, data.Length);
      param.Value = data; 
      
      etc...
      

      【讨论】:

        【解决方案6】:

        有理由保持灵活。不应允许数据库结构的规则或指导方针阻碍创造力。鉴于这里的第一个线程,我可以看到一种混合方法来存储序列化列和约束列。通过保持对可能性的开放态度,许多应用程序可以得到极大的改进。

        无论如何,我很欣赏新手对此事的看法。让我们保持新鲜..

        【讨论】:

          【解决方案7】:

          我在关系数据库方面的经验比 c# 多,但二进制序列化是一种可接受的方式,因为它允许将整个对象的状态保存到数据库中。 XML 序列化几乎相同,但不允许使用泛型类型。

          【讨论】:

          • 次要更正:如果您使用 DataContract 序列化或 NetDataContract 序列化,而不是 XML 序列化,则允许使用泛型类型。
          猜你喜欢
          • 1970-01-01
          • 2021-06-27
          • 1970-01-01
          • 2022-01-03
          • 1970-01-01
          • 2015-08-31
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多