Posts

....
Technical Blog for .NET Developers ©

Wednesday, May 29, 2013

Serialization

Serialization is the act of taking an in-memory object or object graph (set of objects that reference each other) and flattening it into a stream of bytes or XML nodes that can be stored or transmitted. Deserialization works in reverse, taking a data stream and re-building it into an in-memory object or object graph

Serialization and deserialization are mostly used with two objectives:

- Transmit objects across a network or application boundary

- Store representations of objects within a file or database


The three main engines in .NET framework for serialization are the next:

- The data contract serializer

- The binary serializer

- The XML serializer


There is also the IXMLSerializable interface, used to implement own code serialization, using XmlReader and XmlWriter

The data contract serializer is the newest and the most versatile of the three serialization engines and is used by WCF

In this example, we will expose how to use the data contract serializer

There are two ways of using this serializer, through DataContractSerializer class, or through NetDataContractSerializer class. NetDataContractSerializerClass tightly types to data contract types, it relies on the presence of a specific .NET type in a specific namespace and assembly in order to deserialize

If you’re saving an object graph to a “black box", you can choose either serializer, depending on what benefits are more important to you. If you’re communicating through WCF, or reading/writing an XML file, it's highly recommended the DataContractSerializer

This is the class to serialize, and the code to serialize/deserialize

     
	namespace Serialization
    {
        [DataContract]
        public class City
        {
            [DataMember]
            public string Name { get; set; }

            [DataMember]
            public int Cityzens { get; set; }
        }
    }
    

     
	City ciudad = new City() { Name = "Barcelona", Cityzens = 1620940 };

    var ds = new DataContractSerializer(typeof (City));

    // Serialize
    using (Stream stream = File.Create("barcelona.xml"))
        ds.WriteObject(stream, ciudad);
 
    // Deserialize
    City bcn;
    using (Stream stream = File.OpenRead("barcelona.xml"))
        bcn = (City)ds.ReadObject(stream);

    Console.WriteLine("{0}: {1}", bcn.Name, bcn.Cityzens);
    

The result of the previous code is the next


<City xmlns="http://schemas.datacontract.org/2004/07/Serialization" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><Cityzens>1620940</Cityzens><Name>Barcelona</Name></City>

DataContractSerializer, and NetDataContractSerializer, both use the XmlFormatter by default, with an XmlWriter, you can request that the xml be intended for readability

     
	City ciudad = new City() { Name = "Barcelona", Cityzens = 1620940 };

    var ds = new DataContractSerializer(typeof (City));

    XmlWriterSettings setts = new XmlWriterSettings() { Indent = true };

    using (XmlWriter writer = XmlWriter.Create("city.xml", setts))
        ds.WriteObject(writer, ciudad);

    System.Diagnostics.Process.Start("city.xml");
    

The result of the previous code is as follows



The XML element name reflects the data contract name, which, by default, is the .NET type name; the XML namespace reflects the data contract namespace, which, by default, is http://schemas.datacontract.org/2004/07/, plus the .NET type namespace. You can override both of them in this way


     
	[DataContract (Name="Ciudad", Namespace="http://innovar.com")]
    public class City
    {
        [DataMember (Name="Nombre")]
        public string Name { get; set; }

        [DataMember (Name="Poblacion")]
        public int Cityzens { get; set; }
    }
    




<METHOD SOFTWARE © 2013>

Friday, May 10, 2013

Profiling LINQ Queries

When we are implementing LINQ queries to retrieve data from our database server, it's a good practice profile the queries through SQL Profiler tool, it might be decisive for improving the query and reducing the time responses

In this example we have our DataContext pointing to a database with a table named B_PRODUCTS, filled with 30000 records for this example

In order to measure the time response of this query into the server side, we will begin a new instance of SQL Profiler tool, and begin a new trace connected to our server



We will make use of the template T-SQL duration, for targeting the duration of the query in milliseconds when is processed by the server. In the events tab of the trace, we can filter the trace log only to those events we want to register



At this point, we run the trace, and launch the query

This is the initial linq query

     
	using (BusinessClassesDataContext context = new BusinessClassesDataContext())
    {
        Products = (from prods in context.B_PRODUCTs
                    orderby prods.Description ascending
                    select prods).ToList<B_PRODUCT>();
    }
    




Now we will include a where clause with 2 conditions and check the trace log

     
		Products = (from prods in context.B_PRODUCTs
                where prods.Description.EndsWith("kit")
                    && prods.IdProduct > 100
                orderby prods.Description ascending
                select prods).ToList<B_PRODUCT>();
                




Now we will change the implementation of the first condition making use of the SqlMethods namespace, the which one includes SQL expressions for querying data

     
		Products = (from prods in context.B_PRODUCTs
                where SqlMethods.Like(prods.Description, "%kit")
                    && prods.IdProduct > 100
                orderby prods.Description ascending
                select prods).ToList<B_PRODUCT>();




With this second approach, we can appreciate a reduction of the time response of 40 milliseconds, with this information we can leverage the most efficient way to query our data


<METHOD SOFTWARE © 2013>

Saturday, May 4, 2013

Solve multiple concurrence with ADO.NET

When we have multiple instances of the same application updating the same database, we have to stablish control for handling the possible concurrence conflicts amidst all requests to the database

In this example we have the next application and data in a grid



The code for submit changes to the database when updated is the next

     
	private void btnUpdate_Click(object sender, EventArgs e)
    {
        commandBuilder = new SqlCommandBuilder(dataAdapterConcerts);
        dataAdapterConcerts.Update(dataSet.Tables["Concerts"]);
        dataSet.AcceptChanges();
    }
    


In order to stablish concurrence control, we are going to implement the event handler RowUpdated of our SqlDataAdapter object

    dataAdapterConcerts.RowUpdated += 
        new SqlRowUpdatedEventHandler(dataAdapter_RowUpdated);


with the next code

     
	private void dataAdapter_RowUpdated(object sender, SqlRowUpdatedEventArgs e)
    {
        if (e.Status == UpdateStatus.ErrorsOccurred)
        {
            solveConcurrence(e.Row);
            e.Status = UpdateStatus.SkipCurrentRow;
        }
    }
    


The method solveConcurrence for the row is as follows

     
private void solveConcurrence(DataRow row)
{
    DataSet actualData = new DataSet();
    dataAdapterConcerts.Fill(actualData, "Concerts");
    dataAdapterHalls.Fill(actualData, "Halls");

    actualData.Tables["Concerts"].PrimaryKey = new DataColumn[] 
        { actualData.Tables["Concerts"].Columns["IdConcert"] };

    DataRow actualRow = actualData.Tables["Concerts"].Rows.Find((int)row["IdConcert"]);

    string message = string.Format("actual value = title: {0} - id hall: {1} - date: {2}
       \r\rproposed value = title: {3} - id hall: {4} - date: {5}",
        actualRow["Title"], actualRow["IdHall"], actualRow["Date"], 
        row["Title"], row["IdHall"], row["Date"]);

    if ((MessageBox.Show("Concurrence conflict\r\rdo you want to override changes?\r\r" 
        + message, "Concerts#",
        MessageBoxButtons.YesNo, MessageBoxIcon.Question)
        == DialogResult.Yes))
    {
        dataSet.Merge(actualData, true);

        dataAdapterConcerts.Update(dataSet.Tables["Concerts"]);

        row.AcceptChanges();
    }
    else
    {
        row["IdConcert"] = actualRow["IdConcert"];
        row["Title"] = actualRow["Title"];
        row["IdHall"] = actualRow["IdHall"];
        row["Date"] = actualRow["Date"];

        row.AcceptChanges();
    }
}


The result of this code when we launch two or more instances of the application and apply different changes on the same row, is the next



Data will be merged or equalized depending on the dialog result


<METHOD SOFTWARE © 2013>