10

I am new to the world of ASP.NET and SQL server, so please pardon my ignorance ...

If I have a data structure in C# (for e.g. let's just say, a vector that stores some strings), is it possible to store the contents of the vector as is in SQL table? I want to do this so that it fast to convert that data back into vector form as fast as possible without having to construct it element by element. Almost like writing binary data to a file and then reading it and copying it to an allocated structure in C.

I've created a table on SQL Server 2008 for which a field is defined as VARBINARY(MAX). I thought I'd start with that.

Could someone show me an example of how I would go about storing and retrieving a vector of, say, 10 strings, into and from that field? Is this even possible (I can't think of why not)?

Thanks!

alienfluid
  • 161
  • 1
  • 2
  • 5

7 Answers7

24

First, there is the obvious route of simply creating a relational structure and mapping the object to fields in the database.

Second, if you have an object that is serializable, you can store it in SQL server. I have done this on occasion, and have used the Text data type in SQL Server to store the XML.

Opinion: I prefer to store serialized objects as XML instead of binary data. Why? Because you can actually read what is in there (for debugging), and in SQL Server you can use XQuery to select data from the serialized object. From my experience, the performance gain of using binary data will not be worth it compared to having data that is easier to debug and can be used in a psuedo-relational fashion. Take a look at SQL Server's XQuery capabilities. Even if you don't plan on using it right away, there is no reason to put yourself in a corner.

You might look at some examples using the NetDataContractSerializer.

I believe what you call a vector is a List<> in C#. Take a look in System.Collections.Generic. You can use the NetDataContractSerializer to serialize a List of 3 strings like:

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

This example just serializes a list, outputs the serialization to the console, and then proves it was hydrated correctly on the flip side. I think you can see that from here you could either dump the memory stream into a string and write that to the database, or use another stream type than a memory stream to do it.

Remember to reference System.Runtime.Serialization to get access to the NetDataContractSerializer.

Jason Jackson
  • 17,016
  • 8
  • 49
  • 74
  • @Jason Jackson I agree with you, when you say **"I prefer to store serialized objects as XML instead of binary data"**, but what if I have to serialize interfaces? – davioooh Feb 03 '12 at 11:58
  • interfaces are not serializable so implemented properties must be ignored...above method is very useful in some cases where you have time consuming operations over data structure creation...i prefer to use JSON serializer that way you will save memory... – A.T. Jun 28 '14 at 12:15
  • I have flip-flopped on XML vs JSON over the last couple of years. My current job has some very unique data storage requirements that has doing a lot of normalized data structures and also a lot of one-offs which we usually store in an nvarchar(max) column as JSON. Lately we have been moving away from NHibernate to Dapper for performance and other reasons and have been doing *a lot* more pure-SQL, and I have found that XML has helped me a few times because T-SQL has XML built in for querying. I think it can become dangerous if overused, but it is dang useful. – Jason Jackson Jul 31 '14 at 15:32
8
[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
    }
}
Vyrotek
  • 5,356
  • 5
  • 45
  • 70
3

Assuming the objects are marked with [Serializable] or implement ISerializable the the BinaryFormatter class gives a simple way to do this.

If not, you're looking at (non trivial) custom code.

Greg Beech
  • 133,383
  • 43
  • 204
  • 250
2

If you're gonna do that (and I guess it's technically possible), you might just as well use a flat file: there's no point in using a relational database any more.

Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
  • 1
    So you're saying that if you need to persist something which doesn't happen to be a built-in database column type, you should instead use flat files? – MusiGenesis Oct 20 '08 at 00:28
  • Why not use a database? It certainly has the advantage of being more scalable than a flat file. And if you use an XML serialization format you can also query on the data in SQL Server using XQuery. – Jason Jackson Oct 20 '08 at 00:32
  • If you're persisting a complex object to a database, each field in the object should get it's own column or table so you can search and query on that field. – Joel Coehoorn Oct 20 '08 at 00:52
  • I agree that using a relational structure makes sense in the vast majority of cases. This fails when you have data that is based on a customizable template. If you don't know what fields will exist at design time, its hard to come up with a normalized data structure in the db. – Jason Jackson Oct 20 '08 at 01:35
  • There is no point in re-creating your object's structure in a relational database UNLESS you abolutely need to query it. And even then, its much simpler and easier to support if you drop your objects in as xpath-queryable xml. –  Oct 20 '08 at 02:04
  • Jason nailed it. I need to store a user-defined set of data which is generated at run-time. There's no need to search it since that data is not indexable or unique, and there's another id that has a one-to-one relationship with this data anyway which what will be used to search the table. – alienfluid Oct 20 '08 at 17:48
  • How is it, then, that you have a struct definition if you don't know the composition until run-time? – Joel Coehoorn Oct 20 '08 at 19:17
  • And hence the dynamically generated vector. Each data point generated at runtime has a well-defined structure and properties, I just don't know how many of those there would be. I am planning on storing them in a list and then serializing the list to a field in the SQL table. – alienfluid Oct 20 '08 at 21:43
2

Here's another more general approach for generic lists. Note, the actual type stored in the list must also be serializable

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

}

Then in client code:

List<string> stringList = new List<string>() { "January", "February", "March" };

byte[] data = SerializeList<string>(stringList);

One basic way of storing/retrieving this array of bytes could be to use simple SQLClient objects:

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

etc...
Ash
  • 60,973
  • 31
  • 151
  • 169
1

There are reasons to be flexible. Rules, or guidelines, for database structure should not be allowed to impede creativity. Given the first thread here, I can see a hybrid approach for storing both serialized and constraining columns as well. Many an application could be vastly improved by keeping ones mind open to possibilities.

Anyway, I appreciated a newbies perspective on the matter. Keeps us all fresh..

Chuck
  • 11
  • 1
0

I have more experience with relational databases than c#, but binary serialization is an acceptable way to go, as it allows the entire object's state to be saved into the database. XML serialization is pretty much the same, although generic types are not allowed.

jle
  • 9,316
  • 5
  • 48
  • 67
  • Minor correction: Generic types ARE allowed, if you use DataContract serialization or NetDataContract serialization, rather than XML serialization. – David White Nov 09 '09 at 02:43