Хранение структуры данных C# в базе данных SQL
Я новичок в мире ASP.NET и SQL-сервера, поэтому прошу прощения за мое невежество...
Если у меня есть структура данных в C# (например, скажем, вектор, в котором хранятся некоторые строки), возможно ли сохранить содержимое вектора, как в таблице SQL? Я хочу сделать это так, чтобы быстро преобразовать эти данные обратно в векторную форму как можно быстрее, не создавая их поэлементно. Почти как запись двоичных данных в файл, а затем чтение и копирование в выделенную структуру на C.
Я создал таблицу на SQL Server 2008, для которой поле определено как VARBINARY(MAX). Я думал, что начну с этого.
Может ли кто-нибудь показать мне пример того, как я буду хранить и извлекать вектор, скажем, из 10 строк, в и из этого поля? Это вообще возможно (я не могу думать, почему нет)?
Спасибо!
7 ответов
Во-первых, существует очевидный путь простого создания реляционной структуры и сопоставления объекта с полями в базе данных.
Во-вторых, если у вас есть объект, который можно сериализировать, вы можете сохранить его на сервере SQL. Я делал это время от времени и использовал тип данных Text в SQL Server для хранения XML.
Мнение: я предпочитаю хранить сериализованные объекты в виде XML вместо двоичных данных. Зачем? Потому что вы действительно можете прочитать, что там (для отладки), а в SQL Server вы можете использовать XQuery для выбора данных из сериализованного объекта. Исходя из моего опыта, выигрыш в производительности от использования двоичных данных не будет стоить того по сравнению с наличием данных, которые легче отлаживать и которые можно использовать псевдо-реляционным образом. Посмотрите на возможности SQL Server XQuery. Даже если вы не планируете использовать его сразу, нет никаких причин, чтобы загнать себя в угол.
Вы можете посмотреть на некоторые примеры, используя NetDataContractSerializer.
Я считаю, что то, что вы называете вектором - это List<> в C#. Посмотрите в 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.
[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
}
}
Предполагая, что объекты помечены [Serializable]
или реализовать ISerializable
the BinaryFormatter
класс дает простой способ сделать это.
Если нет, вы смотрите на (не тривиальный) пользовательский код.
Если вы собираетесь это сделать (и я думаю, что это технически возможно), вы также можете использовать плоский файл: больше нет смысла использовать реляционную базу данных.
Вот еще один более общий подход для общих списков. Обратите внимание, что фактический тип, хранящийся в списке, также должен быть сериализуемым.
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...
Есть причины быть гибкими. Правила или руководящие принципы, касающиеся структуры базы данных, не должны препятствовать творчеству. Учитывая первый поток здесь, я вижу гибридный подход для хранения как сериализованных, так и ограничивающих столбцов. Многие приложения могут быть значительно улучшены, если держать их открытыми для возможностей.
Во всяком случае, я оценил перспективу новичков по этому вопросу. Держит нас всех свежими..
У меня больше опыта работы с реляционными базами данных, чем C#, но двоичная сериализация - приемлемый путь, поскольку она позволяет сохранить все состояние объекта в базе данных. Сериализация XML почти такая же, хотя универсальные типы не допускаются.