1

I just need to do the reverse conversion as exposed in this question.

I have a MemoryStream and want to store it in a System.Data.Linq Binary field of my SQL CE database (FYI I'm using EF code first).

The MemoryStream is actually a XML, which is larger than the max size of a String field, so I found no other way than storing it in a Binary (suggestions on this subject REALLY appreciated).

My code (adapted)

   private Stream _userLayout;
   _userLayout = new MemoryStream();
   DXGridControl_Table.SaveLayoutToStream(_userLayout);
   MyDatabse.SomeTable.SomeBinaryField = _userLayout.????
Community
  • 1
  • 1
Hannish
  • 1,482
  • 1
  • 21
  • 33

3 Answers3

4

MemorySteam class has ToArray() method:

MemoryStream.ToArray Method:

Writes the stream contents to a byte array, regardless of the Position property.

This method returns a copy of the contents of the MemoryStream as a byte array. If the current instance was constructed on a provided byte array, a copy of the section of the array to which this instance has access is returned. See the MemoryStream constructor for details.

This method works when the MemoryStream is closed.

With byte[] you can easily get Binary instance, because Byte[] to Binary implicit conversion is available:

MyDatabse.SomeTable.SomeBinaryField = (Binary) _userLayout.ToArray();
Community
  • 1
  • 1
MarcinJuraszek
  • 124,003
  • 15
  • 196
  • 263
  • Thank you Marcin for taking time to answer. I must be missing something very simple here, but when I type "(Binary) _userLayout.ToArray();" or casting like this ((Binary)_userLayout).ToArray(); I get a "Cannot convert type System.IO.MemoryStream to System.Data.Linq.Binary. Any idea why this is happening? – Hannish Mar 30 '13 at 18:50
3

First there is

        byte[] buffer = new byte[LENGTH];
        MemoryStream memoryStream  = new MemoryStream(buffer);

In your example you can use

        DXGridControl_Table.SaveLayoutToStream(_userLayout);
        byte[] doSomethingwithyourData = _userLayout.GetBuffer();
        var length = _userLayout.Length;

With that information you can write the binary data to whatever.

Note that the buffer contains allocated bytes which might be unused. For example, if the string "test" is written into the MemoryStream object, the length of the buffer returned from GetBuffer is 256, not 4, with 252 bytes unused. To obtain only the data in the buffer, use the ToArray method; however, ToArray creates a copy of the data in memory.

Or

Binary binary = new Binary(_userLayout.ToArray());

Like in the other answer said, there is an implicit conversion on binary:

public static implicit operator Binary(byte[] value) {
    return new Binary(value); 
}

You requested examples. A little example about the usage:

namespace Stackoverflow.Hannish.SaveLayout
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Text;
    using System.Windows.Forms;

    public partial class Form1 : Form
    {
        /// <summary>
        /// Here we store the layout data as a string. This is the data, that
        /// gets saved to disk / database / etc.
        /// </summary>
        private string layoutdata = string.Empty;

        public Form1()
        {
            this.InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            // Just some FooBar data.
            var data = new List<DataValue>
                           {
                               new DataValue { Id = 1, Name = "Xyz", IsCool = true }, 
                               new DataValue { Id = 2, Name = "Abc", IsCool = false }
                           };

            this.gridControl1.DataSource = data;
        }

        private void bnLoadLayout_Click(object sender, EventArgs e)
        {
            using (var stream = new MemoryStream())
            {
                var strdata = Encoding.Default.GetBytes(this.layoutdata);
                stream.Write(strdata, 0, strdata.Length);
                stream.Seek(0, SeekOrigin.Begin);
                this.gridView1.RestoreLayoutFromStream(stream);
            }
        }

        private void bnSaveLayout_Click(object sender, EventArgs e)
        {
            using (var stream = new MemoryStream())
            {
                this.gridView1.SaveLayoutToStream(stream);
                this.layoutdata = Encoding.Default.GetString(stream.ToArray());
            }
        }
    }
}

And some byte to file magic:

    private void bnLoadBinLayout_Click(object sender, EventArgs e)
    {
        using (FileStream fstream = File.Open("Layoutdata.bin", FileMode.Open))
        {
            int length = (int)fstream.Length;
            byte[] buffer = new byte[length];
            fstream.Read(buffer, 0, length);

            var memstream = new MemoryStream(buffer);
            this.gridView1.RestoreLayoutFromStream(memstream);
        }
    }

    private void bnSaveBinLayout_Click(object sender, EventArgs e)
    {
        using (FileStream fstream = File.Create("Layoutdata.bin"))
        {
            var memstream = new MemoryStream();
            this.gridView1.SaveLayoutToStream(memstream);
            fstream.Write(memstream.GetBuffer(), 0, (int)memstream.Length);
        }
    }

... just as example. DevExpress GridView can save the layout itself with SaveLayoutToXml();

Jedzia
  • 116
  • 1
  • 6
  • Jedzia, care to give an example of your comment "With that information you can write the binary data to whatever." suited for this scenario? As you can see, I'm not used to work with streams and Binary types, so please indulge me. – Hannish Mar 30 '13 at 18:54
  • 2
    I added "A little example about the usage:" in the answer above. Hope it helps :) – Jedzia Mar 31 '13 at 11:59
  • Given the great and thorough examples I think this is the best answer, thank you very much!!! – Hannish Mar 31 '13 at 15:24
  • 1
    Always glad to help. P.S.: I forgot to clarify that **SaveLayoutToStream()** and **RestoreLayoutFromStream()** can work on the FileStream alone, without the detour over **MemoryStream**. I just showed it as example on "playing" with bytes.:) – Jedzia Apr 01 '13 at 00:31
1

To your second question and your (possible) conceptual mistake of converting the data back and forth.

Save that funny DevExpress XML in a ntext data column.

ntext: Variable-length Unicode data with a maximum length of (2^30–2)/2 (536,870,911) characters. Storage size, in bytes, is two times the number of characters entered.

See SQL Server Compact 4.0 Data Types

Jedzia
  • 116
  • 1
  • 6
  • Thank you Jedzia. Your answer raises two more questions... how do I define an ntext field with code first approach (string properties are translated to nchar fields in the DB), and what does the note in your link mean? "ntext is no longer supported in string functions". Thanks – Hannish Mar 30 '13 at 18:44
  • Actually, this is the answer that seems the best option for me, since I could avoid the conversion to/from binary altogether, since the funny DevExpress component also has a "SaveLayoutToXML" method, which I assume I could store directly in such a DB field. – Hannish Mar 30 '13 at 19:08
  • Please have a look at http://stackoverflow.com/questions/11365186/ntext-with-more-than-4000-characters-in-sql-server-ce-in-windows-phone?answertab=oldest#tab-top about defining ntext fields (read and check the microsoft KB stuff). – Jedzia Mar 31 '13 at 12:26
  • 1
    The note means, that you follow the link 1) :P -> http://msdn.microsoft.com/en-us/library/bb896140.aspx _snip_ **Not supported**: * Aggregate value expressions contain ntext or image data types. * Large objects, for example, ntext and image data types, in ORDER BY clauses. * ntext and image data types cannot be used in WHERE, HAVING, GROUP BY, ON, or IN clauses, except when these data types are used with the LIKE or IS NULL predicates. * Alter column of type ntext or image. _snap_ Thats nothing you want to do with the XML-Layout-Data, i hope. – Jedzia Mar 31 '13 at 12:31
  • Jedzia, this answer REALLY helped me, and your comments too. I accepted your other answer though, because it's the one that fits better the main question, but know that I ended up using your suggestion here and it works great! Regarding the comments, I don't need to query based on this column, so it's ok even with these restrictions. You've been VERY helpful. – Hannish Mar 31 '13 at 15:31