Another challenge in working with tiered solutions (notably web services) that require xml serialization of entity objects is that the xml serializer does not serialize the entire graph. It only gets the main object and drops all of the relations. This is not because Entity Framework is trying to be mean, just related to how XML serialization works. In fact, the binary serialization gets the entire graph. But in the web services scenarios, we need XML.
So how to go about passing the full graph from client to server and back or server to server? I had a few ideas of how to approach this but was given a suggestion by Danny Simmons that would help me create something that would be more aligned with what their thinking on this is.
This solution uses a facade pattern. It is possible because the individual objects are serializable and a generic List is serializable. Conceptually, I take all of the objects in the graph that may start out, for example as:
and create Lists of each set of objects then combine those lists into another object. After this is created, the above would look like this
-List(Of Customer) –> would only contain one
Deserializing would mean pulling the customer out of the first list, then iterating through the list of orders and adding each order to that customer.
It gets a little more complicated when dealing with deeper graphs.
now we need to serialize a bit more carefully
The OrderswithDetails would be another object that looks like this
The OrderwithDetails class that implements the facade will need these features:
- A property to contain List(Of Order)
- A property to contain List(Of OrderDetails)
- if we are going deeper then this property should be List(Of OrderDetailswithChildren)
- Instantiation code needs to take in the original object and construct the lists
- A method that knows how to deserialize the object and return the real object, not the lists of it’s parts
- If this is going to be used in a wcf service, the class needs to be marked as a DataContract and the properties should be marked as DataMembers.
Here is what a simple class for serializing/deserializing the orders with their orderDetails (without considering any possible children of orderDetails right now). This is my first pass at this class and therefore it is not generic code that will work with any complex object. However, it does work out the basic logic (and it does work!).
Public Class SalesOrderwithDetailsGraph
Dim _order As List(Of SalesOrderHeader)
Dim _orderdetails As List(Of SalesOrderDetail)
Public Sub New()
‘required for serialization
Public Sub New(ByVal salesOrderGraph As SalesOrderHeader)
_order = New List(Of SalesOrderHeader)
If salesOrderGraph.EntityState <> EntityState.Detached Then
‘if I’m just creating the order for the first time and am attached to the context,
‘this assumes that I didn’t Include salesorderHeaders in my query – big assumption, but
‘it is just for my proof of concept. If it’s detached, then I am already working with a
‘full object and can’t load anyway – that requires a context and a connection
_orderdetails = New List(Of SalesOrderDetail)(salesOrderGraph.SalesOrderDetail)
Public Property Order() As List(Of SalesOrderHeader)
Set(ByVal value As List(Of SalesOrderHeader))
_order = value
Public Property OrderDetails() As List(Of SalesOrderDetail)
Set(ByVal value As List(Of SalesOrderDetail))
_orderdetails = value
Public Function GetOrderFromGraph() As SalesOrderHeader
‘this is to Deserialize
Dim ord As SalesOrderHeader
‘there will only be one header in the object
ord = _order(0)
For Each sod As SalesOrderDetail In _orderdetails
Now, if i have a simple scenario where I have a client that requests an order from a web service, mucks with that order, then sends it back to the service for an update, the client can start by retrieving a SalesOrderGraph, deserializing it back to a SalesOrder, then when it’s done, create a SalesOrderGraph from the existing SalesOrder and pass it back up to the Service.
There’s one big missing piece here and I blogged about that yesterday. When the order gets back to the service for an update, if you plan to update through the objectContext, then you will need to manually set the state to modified. You can do this with or without original data (depending on whether or not you care about concurrency). See my blog post about Disconnected Entities.
Lastly, I have actually gone the next step with the above serializer so that i can get a Customer with Orders and OrderDetails. It means bulding a CustomerGraph just as I built the Order Graph, but the children of the Customer will be SalesOrderwithDetailGraph objects, rather than just SalesOrderHeaders. Then you get a recursive thing happening where the customer knows how to work with it’s orders, and each order know how to work with it’s details.
But this post is long enough already, eh?
Sign up for my newsletter so you don't miss my conference & Pluralsight course announcements!