[important: this post belongs to a whole host of other posts. Basically it's about my efforts of building a light-weight n-tier disconnected solution for Entity Framework]
Another status update. I've worked on connecting up a clean graph to a EntityFramework context and found it far from straight-forward! I ended up with very little code though, which is a good sign.
The approach of not serializing the object context, makes it harder to figure out when an object was added or removed. On the client, I keep copies of the 'original' collection and I compare the new collection with the old collection. Problem there is that it's quite possible that an object was just removed from a collection and added to another collection. How do we know we have to do a real 'delete' on it?
I have not yet figured this out 
Here is some code for you to look at:
0 Customer c = new Customer { Name = "Ruurd Boeke" }; 1 Car car1 = new Car { Make = "Saab", Customer = c };
2 Order order1 = new Order { Amount = 2, Customer = c }; 3
4 5 IEditableBusinessObject eC = c as IEditableBusinessObject;
6 string MsgOnWire = ""; 7
8 // at this point, we are not at all attached 9 using (SimpleRelationshipTestEntities context = new SimpleRelationshipTestEntities())
10 { 11 context.AddToCustomer(c);
12 context.SaveChanges(); // this instructs context to start changetracking 13
14 ((IContextAware)c).CreateSerializableState(context); 15
16 DataContractSerializer s = new DataContractSerializer(c.GetType(), null, int.MaxValue, false, false, new SubstituteDomainDataContractSurrogate()); 17
18 MsgOnWire = s.GetWellFormedToContract(c); 19 }
20 The message on the wire looks like this:
<CustomerSurrogate xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="myNamespace">
<Cars>
<Car>
<CarID>244</CarID>
<Customer>
<SerializationID>0</SerializationID>
</Customer>
<Make>Saab</Make>
<SerializationID>1</SerializationID>
<OriginalValue_CarID>244</OriginalValue_CarID>
<OriginalValue_Customer>
<SerializationID>0</SerializationID>
</OriginalValue_Customer>
<OriginalValue_Make>Saab</OriginalValue_Make>
</Car>
</Cars>
<CustomerID>152</CustomerID>
<Name>Ruurd Boeke</Name>
<Orders>
<Order>
<Amount>2</Amount>
<Customer>
<SerializationID>0</SerializationID>
</Customer>
<OrderID>159</OrderID>
<SerializationID>2</SerializationID>
<OriginalValue_Amount>2</OriginalValue_Amount>
<OriginalValue_Customer>
<SerializationID>0</SerializationID>
</OriginalValue_Customer>
<OriginalValue_OrderID>159</OriginalValue_OrderID>
</Order>
</Orders>
<SerializationID>0</SerializationID>
<OriginalValue_Cars>
<Car>
<SerializationID>1</SerializationID>
</Car>
</OriginalValue_Cars>
<OriginalValue_CustomerID>152</OriginalValue_CustomerID>
<OriginalValue_Name>Ruurd Boeke</OriginalValue_Name>
<OriginalValue_Orders>
<Order>
<SerializationID>2</SerializationID>
</Order>
</OriginalValue_Orders>
</CustomerSurrogate>
Next step is to receive this xml on the client, deserialize it and change some stuff:
0 DataContractSerializer s2 = new DataContractSerializer(typeof(CustomerClient), null, int.MaxValue, false, false, new SubstituteDomainDataContractSurrogate());
1 CustomerClient c2 = (CustomerClient)s2.UnwrapFromString(MsgOnWire);
2
3 // delete
4 c2.Cars.First().Customer = null;
5 c2.Cars.Clear();
6
7 // add
8 OrderClient order2 = new OrderClient { Amount = 100, Customer = c2 };
9 c2.Orders.Add(order2);
10
11 // change
12 c2.Name = "Changed";
13
14 // we have edited everything, let's get back to the server
15 DataContractSerializer s3 = new DataContractSerializer(typeof(CustomerClient), null, int.MaxValue, false, false, new SubstituteDomainDataContractSurrogate());
16 MsgOnWire = s3.GetWellFormedToContract(c2);
This client is removing the cars. Note that we do not get the automatic hookup of relations that we used to get on the server: there is no EF Relationship manager on the client!
<CustomerSurrogate xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="myNamespace">
<Cars />
<CustomerID>152</CustomerID>
<Name>Changed</Name>
<Orders>
<Order>
<Amount>2</Amount>
<Customer>
<SerializationID>0</SerializationID>
</Customer>
<OrderID>159</OrderID>
<SerializationID>1</SerializationID>
<OriginalValue_Amount>2</OriginalValue_Amount>
<OriginalValue_Customer>
<SerializationID>0</SerializationID>
</OriginalValue_Customer>
<OriginalValue_OrderID>159</OriginalValue_OrderID>
</Order>
<Order>
<Amount>100</Amount>
<Customer>
<SerializationID>0</SerializationID>
</Customer>
<SerializationID>2</SerializationID>
</Order>
</Orders>
<SerializationID>0</SerializationID>
<OriginalValue_Cars>
<Car>
<CarID>244</CarID>
<Make>Saab</Make>
<SerializationID>3</SerializationID>
<OriginalValue_CarID>244</OriginalValue_CarID>
<OriginalValue_Customer>
<SerializationID>0</SerializationID>
</OriginalValue_Customer>
<OriginalValue_Make>Saab</OriginalValue_Make>
</Car>
</OriginalValue_Cars>
<OriginalValue_CustomerID>152</OriginalValue_CustomerID>
<OriginalValue_Name>Ruurd Boeke</OriginalValue_Name>
<OriginalValue_Orders>
<Order>
<SerializationID>1</SerializationID>
</Order>
</OriginalValue_Orders>
</CustomerSurrogate>
We see that there are no current cars, but the original value of cars still has them. That is how I figure out to delete the cars on the server.
Did you also notice how the new order does not have a ID assigned? The server will take care of it.
0 // we're at the server
1 using (SimpleRelationshipTestEntities context = new SimpleRelationshipTestEntities())
2 {
3 DataContractSerializer s4 = new DataContractSerializer(typeof(Customer), null, int.MaxValue, false, false, new SubstituteDomainDataContractSurrogate());
4 Customer c3 = (Customer)s4.UnwrapFromString(MsgOnWire);
5
6 ((IContextAware)c3).AttachGraphToContext(context,
7 delegate(object source)
8 {
9 return source.GetType().Name; // our setnames correspond to our classname.
10 });
11
12
13 context.SaveChanges();
14 }
Now, we're deserializing and attaching the graph to the context. The delete on line 7 is a way of returning entitysetnames. EF needs to know the entitysetname to be able to attach an object to a context, but there is no way for me to know it. So at this point I let you make the decision yourself.
The database is correctly filled and we are happy.
Now, I really want to check in this source, but there is a lot to be done still. The API I have created is monstrous.
Also, I think there are quite a few situations where this will break horribly.
Once I get just a little happier about it, I will do a screencast building a server using Entity Framework and a silverlight client that is editing.