我能在SQL Server数据库中保存“对象”吗?

54

我想将一个对象(任何类型)保存到SQL Server 2005数据库中的字段中。这是否可能?我需要将对象转换为类似字节数组的东西,并在检索时将其转换回来吗?


2
您也可以序列化为 XML,这比二进制数据更容易在数据库内检查。 - pjp
1
这不是一个很好的数据库设计。你是否需要在任何时候查询对象的属性?例如,获取所有对象其中对象.Foo = 1。 - Paddy
不需要了解或查询存储表的内容。 - Ahmad Farid
5个回答

36

如果需要的话,您可以在 SQL Server 中使用 VARBINARY(MAX) 字段类型。您可以在其中存储任何类型的对象,最大大小为 2 GB。

要访问它,您可以使用 ADO.NET - 类似于这样:

object yourMysteryObject = (whatever you like it to be);

MemoryStream memStream = new MemoryStream();
StreamWriter sw = new StreamWriter(memStream);

sw.Write(yourMysteryObject);

SqlCommand sqlCmd = new SqlCommand("INSERT INTO TableName(VarBinaryColumn) VALUES (@VarBinary)", sqlConnection);

sqlCmd.Parameters.Add("@VarBinary", SqlDbType.VarBinary, Int32.MaxValue);

sqlCmd.Parameters["@VarBinary"].Value = memStream.GetBuffer();

sqlCmd.ExecuteNonQuery();

Marc


但是我如何将一个对象转换为VARBINARY类型? - Ahmad Farid
但这是从文件中读取的图像。如果我有一个在运行时创建的类或对象,与文件无关,该怎么办呢? - Ahmad Farid
哈哈,你的神秘对象真好玩 :D 谢谢老兄 :) 当重新检索它时,正常类型转换对吧? - Ahmad Farid
如果你想要它回来,你必须知道你得到了什么!SQL Server只会发送任意数量的字节 - 是你必须知道它是什么以及如何将字节流转换回对象。 - marc_s
7
什么?如果你向sw.Write()方法传递一个通用的对象,它只是调用该对象的ToString方法!这并不会对其进行序列化! - AnotherParker
显示剩余4条评论

32

我会使用JSON将该对象转换为字符串,并将其存储在VARCHAR或TEXT字段中。不仅数据以可读的形式存储,而且从不同的语言阅读也很方便,因为几乎每个主流语言都有可用的JSON解析器。

我发布的链接中包含许多语言(包括C#)的几个库的链接,我过去使用过这一个


15

如果您正在使用实体框架(EF),这里有一个示例:

using (DbContext db = new DbContext())
{
    // The object that you want to serialize. In this case it is just an empty instance
    YourObject objectToSerialize = new YourObject();
    IFormatter formatter = new BinaryFormatter();
    using (MemoryStream stream = new MemoryStream())
    {
        formatter.Serialize(stream, objectToSerialize);

        // EF model. In one of its properties you store the serialized object
        YourModel modelObject = new YourModel();

        // In your model 'SerializedObject' should be of type byte[]. In the database it should be of type varbinary(MAX)
        modelObject.SerializedObject = stream.ToArray(); 
        db.YourModel.Add(modelObject);
        db.SaveChanges();
    }
}

这是如何反序列化对象的方法:

// De-serialize
IFormatter formatter = new BinaryFormatter();
Stream stream = new MemoryStream(serializedObject);
YourObject deserializedYourObject = (YourObject)formatter.Deserialize(stream);
stream.Close();

你如何将它转换回我们刚保存的对象...显然要知道原始对象是什么。 - Piotr Kula
1
@ppumpkin。我已经更新了我的答案,提供了如何反序列化对象的信息。祝编码愉快 :) - Ivo Stoyanov
1
被序列化的类必须标记为 Serializable 属性。 - Elton

13

正如其他人所说,序列化可能是关键(假设您不想使用ORM将属性存储为表中的列,这似乎更直接)。

但是要注意以下几点:数据库是:

  • 长期存储
  • 与您的.NET代码无关

因此,您不希望使用任何特定于平台或版本的序列化技术。您经常会看到人们提到BinaryFormatter用于持久性,但这会陷入上述两个陷阱。如果您改变了平台甚至只是更改一些属性,您就会受挫。

您需要一种独立于实现的方法;最简单的方法(也保留了可读性)是xml或json,可能通过XmlSerializer或Json.NET进行(存储在[n]varchar(max)中)。如果您不关心可读性,则“协议缓冲区”(快速/二进制)也很好(存储在varbinary(max)中),并且可用于大多数平台(包括C#/.NET等)。


1

1
但是我不想将它保存在硬盘上,我只想将它放在数据库中。 - Ahmad Farid
11
BinaryFormatter 是长期存储的一个非常糟糕的选择。 - Marc Gravell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接