jake's blog

Serializing Entity Framework Things

There are two flavors of serialization you can use on Framework entities:  good ol' XML serialization and the DataContract serialization.

XML serialization is pretty straightforward - it serializes the object it's given.  But it does not walk references (I'm talking foreign keys here) or collections.  whereas the DataContract serializer does handle the references and keeps track of what objects have been serialized and what hasn't.

If you're going to use XSLT on the serialization, I'm not sure at this point which one is better - they're probably equal but time will tell.

Unfortunately you can't directly serialize the entire ObjectContext, only collections or individual objects can be serialized.  But this isn't as bad as it sounds as usually you'll want to start at some 'master object' in a collection and serialize it and all it references, so the inability to directly serialize the Context is not a big loss.

So how do you do it?

Assume we have a Context named RecipeModel which holds a bunch of recipes and related items (ingredients, techniques, etc.) and we want to serialize a specific recipe and all the ingredient info and technique info that it references. 

First find the Recipe:

  Recipe recipe = RecipeData.Recipes.Find( r => r.Name == targetName );

Then setup the serializer:

  using ( FileStream fs = File.OpenWrite( "RecipeData.xml" ) ) {
      XmlWriter writer = XmlWriter.Create( f2 );
      XmlSerializer srlz = new XmlSerializer( typeof( Recipe ) );
      srlz.Serialize( writer, recipe );
      writer.Close(); // ensure it's properly flushed
  }

That's it. Recipe and all its data are now in the file. But the foreign key references to things like ingredients and techniques aren't there.  If you want to include them you'll need to provide a wrapper which references them directly.  Ugly if you have a lot of different scenarios you need to address.  But for one or two it may not be too much work.

On the other hand, you can use the DataContractSerializer - it handles the foreign key stuff nearly magically.  Try this:

  using ( FileStream fs = File.OpenWrite( "RecipeData.xml" ) ) {
      XmlDictionaryWriter writer = XmlDictionaryWriter.CreateTextWriter( fs, Encoding.UTF8 );
      DataContractSerializer srlz = new DataContractSerializer( typeof( Recipe ) );
      srlz.Serialize( writer, recipe );
      writer.Close(); // ensure it's properly flushed
  }

That's it. The Recipe and all data it references via keys are collected into a single serialization.

But of course there's a caveat or two.  What if the referenced objects/collections aren't loaded?  Does this somehow load them prior to serialization?  Nope - if the referenced objects aren't loaded then all you'll get serialized is the keys that refer to them.   If you want the data then make sure it's loaded.

  recipe.Ingredients.Load();
  recipe.Techniques.Load();

Or some such.  Of course there is a better way - using a LinQ query to eager load the references (and isn't there normally a query involved in all this anyways?):

  srlz.Serialize( writer,
    ( from rcp in model.Recipes.Include( "Ingredients" ).Include( "Techniques" )
      where rcp.Name = "Bordelaise Sauce"
      select rcp ).First() 
  );      

Two things: using the "Include()" forces eager loading of the entire referenced graph (whih in this case is probably what's needed) and second, notice the First() method on the query - this forces the query to execute and returns a single object rather than the query object itself (you can't serialize an ObjectQuery).

Obvioulsy if you're needing to deserialize back to objects, the DataContract method is the way to go but if you're needing to translate your database data to something else (which is what I need to do) then XML/XSLT is worth a look and the above serializers will get half the job done with virtually no pain.

XSLT on the other hand.....

ObjectListView & Dynamic Columns,generic method,attributes

ObjectListView has got to be one of the slickest controls out there - simple, quick and powerful.  But being the extremely lazy coder that I am, it wasn't easy enough. 

So here's a little helper which allows you to decorate a class' properties with an attribute which is used to build the column definitions for the ObjectListView. Define your properties, adorn with an attribute and hand a collection to the listView - the rest is pretty much magic.

I won't explain more here, the documentation has examples: here.  Follow the Class List to OLVColumnAttribute and scroll down to the examples.

Download here.

There's also a demonstration of dynamically invoking a generic method in the ColumnBuilder stuff.

 

EntityObject & Custom Attributes - A Thought

As slick as the EF is, there are limitations (one being my refusal to take 3 days to read MS's disjoint documentation).

A case in point:  An EntityObject classis defined as partial so one may add necessary properties, methods, attributes, etc. at will.  But the generated properties (database column accessors) do not allow for custom attributes.  They're not partial and C# doesn't allow for partial properties anyway.  

So how to add things like DisplayName or DefaultValue or something more esotaric like UnitType(Unit.Meter)?

Searching high and low renders nothing except some obscure references to System.ComponentModel.DataAnnotations.MetadataType(type).  So far I've found nothing definitive - the discussions seem related to the ASP end of things rather than the Forms.

Here, here and here.

It seems that the meta data can be extended via an associated class (MetadataType) but only if TypeDescriptor is used to fetch the metadata.  There may be no general solution to this issue but maybe an application specific solution can be created.

  • Create a custom reflection method that
    • Uses the MetadataType attribute
    • Combines the referenced attributes into the normal custom attributes (using standard reflection)

On the other hand, if I'm forcing the use of a special method to gather attributes, why not just use the TypeDescriptor approach?

More later....

Adding Entities

Once a BindingSource is hooked to a LinQ EF query, editing/deletion become trivial.  But how about adding new objects?

My first attempt, it turns out, was just backwards:  I added a new object to the EntitySet and then added that new object to the BindingSource.  While this worked, it causes havoc in the ObjectStateManager - key inconsistencies, etc.

Turns out the pattern is this:

Add a new object via the BindingSource:

User u = (User)UserVarBindingSource.AddNew();

That's it.  The new object is created and added to the underlying list (in this case the EntitySet) and the BindingSource will position itself (and all bound Controls) to the new records.

But that's not quite the end of the story - the new object probably requires some type of initialization and if that's explicitly done in a default constructor then it needs to be done as a result of the add operation.

We make use of the BindingSource's AddingNew event to set a flag indicating that a new object is added:

private void UerBindingSource_AddingNew( object sender, AddingNewEventArgs e )
{
    m_adding = true;
}

Then utilizing the CurrentChanged event (after the object is added the BindingSource sets it as the current object, triggering this event) the new object is initialized:

private void UserBindingSource_CurrentChanged( object sender, EventArgs e )
{
    // adding new object flag set in AddingNew event handler
    if ( ! m_adding )
        return;
    // reset the flag so we don't modify every object viewed
    m_adding = false;

    //
    // fetch the new object and dress it up
    Model.User usr = (Model.User)UserBindingSource.Current;
    sv.name = "NoName";

    ....

    // The object is stil in the 'edit' state which means the changes will not 
    // be propogated to the underlying layer - end the edit so the object is "live".
    sysVarBindingSource.EndEdit();
}

The call to EndEdit is important - either at this point or prior to saving the data:  if EndEdit isn't called, the BindingSource does not propogate changes to the underlying data store (hmmmmmm....  undo anyone?).

Binding Entities to Form Controls

Binding Entities to Forms controls - easily done but not easily divined.

The naive would hook a LinQ query to the BindingSource's DataSource - and would be rewarded with a functional binding - most of the time.  In fact for read only lists of things this may be acceptable (adding/deleting objects causes inconsitencies in the ObjectManager).  One piece of advice I ran across is to not use this type of binding because every time the BindingSource moves to a different record it rexecutes the query (not confirmed by my testing but it may be true) which could be handy in a highly concurrent environment.

After much gnashing and googling I came across the "proper" way to do this (actually it's in book: "Programming Entity Framework" - O'Reilly"):

ObjectQuery<User> query;
...
query = ( from var in m_model.Users
          orderby var.sortorder, var.name
          select var
          ) as ObjectQuery<User>;
userBindingSource.DataSOurce = query;

As long as you cast the LinQ query to a ObjectQuery<T>, the BindingSource coordinates everything properly.

 

Typing: The query is run on the EntitySet while the ObjectQuery<T> is typed to the underlying object.

With Distinction

I wanted to fire an event when a particular entity type is updated in the store. For example, when any value in a table is modified. How to do it? The context's SavingChanges event is the entry but how to determine which type of data is getting updated? Enter the ObjectStateManager. It'll return collections based on object states, modified, new, deleted, etc. All we need to do is examine the modified objects and fire events based on their types, right? Not so fast - the state manager returns ALL the objects being saved, so there could be many, many entities of any given type and simply firing events when we see a prticular type would result in many unnecessary events. Enter a Distinct Linq query:
var entSets = ( from obj in ObjectStateManager.GetObjectStateEntries( EntityState.Modified )
                        select obj.EntitySet ).Distinct();
This query will gather the EntitySet references from all the objects being saved. Notice the oarens around the query and the Distinct() tacked on the end - this will filter the set to eliminate duplicates - so when we iterate the set, we get exactly one instance of each affected EntitySet. Then we match the EntitySet to an event and we're done. abbreviated...
            foreach ( var set in entSets.Distinct() ) {
                if ( set.Name == "SysVars" )
                    log.Info( "SysVars Modified" );
            }

Deferred Identities

So how does one use identity keys (a.k.a AutoIncrement IDs) with Entities? It's simple. Really. Just not quite what I expected. Assume this table:
CREATE TABLE svar (
	id INTEGER PRIMARY KEY NOT NULL, 
	name NVARCHAR(32) DEFAULT NULL,
);
Simple. Inserting a record should increment the id field ensuring that it's always unique. But the Entities thing has no provisions for this - or does it? It's not in the GUI (yet?), you have to edit the XML (.edmx) directly, adding an attribute to the column definition:
StorageGeneratedPattern="Identity"
This informs the EF system that the column is generated on insert and that it's to read back the value immediately after an insert - which it appears to do.
StorageGeneratedPattern="Computed"
This tells the EF system that the column is computed on update (or insert) and is to be read back immediately after an update,
StorageGeneratedPattern="None"
The default case - do nothing.
So, for the above table, modify the .edmx file like below (in the SSDL section):
        <EntityType Name="svar">
          <Key>
            <PropertyRef Name="id" />
          </Key>
          <Property Name="id" Type="integer" Nullable="false" StoreGeneratedPattern="Identity" />
          <Property Name="name" Type="nvarchar" MaxLength="32" />

Like tunneling through putty

Here's the problem: At work there's an internal web server which holds all kinds of info that's not for public eyes but I'm too lazy to drive to work to update logs or to see what's going on, so how to get to the internal server without just blowing a hole in the firewall? PuTTy to the rescue (again). The firewall already has an ssh port forward to the gateway system. Putty allows forwarding a local port to a remote machine:port. So setting a local port (pick a number like 5432) and forwarding it to the internal server:80 sets up the tunnel. In Mozilla, setup a proxy on localhost:5432 and ALL (and I mean all) traffic is routed to the server behind the firewall. Slick. Putty allows for multiple ports - so I forward the standard svn ports at the same time. Then by directing scn to localhost, all traffic is routed automagically to the server behind the firewall.

LinQ and Forms

Iterating a Form's controls:
var qry = from c in this.Controls.OfType<Control>()
              select c;
foreach ( var c in qry )
    MessageBox.Show( c.Name + ":" + c.GetType().ToString(), "Control Type" );
The Controls collection is not directly usable in the query - the OfType method performs the necessary conversions. To grab all controls of a specific type:
var q2 = from c in this.Controls.OfType<NumericUpDown>() select c;

Lambda & Forms

Lambda expressions and statements: In the context of Forms programming, is there an advantage over anonymous methods? The lambda form is certainly more succinct and (with a bit of practice) simpler to read. Examples: Some simple callbacks as expressions:
// pop a message
button.Click += ( sender, args ) => MessageBox.Show( "Click" );
// increment a numeric updn
button.Click += ( sender, args ) => number.Value = number.Value + 1;
Here's the same things as anonymous methods:
button.Click += delegate( object sender, EventArgs e ) { MessageBox.Show( "Click" ); }
button.Click += delegate( object sender, EventArgs e ) { number.Value = number.Value + 1; }
Slightly more complex callback as a lambda statement (note the enclosing {}):
this.FormClosing += ( sender, args ) => {
    if ( MessageBox.Show( "Really?", "Quit?", MessageBoxButtons.OKCancel ) != DialogResult.OK )
        args.Cancel = true;
};
And as an anonymous method:
button.Click += delegate( object sender, FormClosingEventArgs args ) {
    if ( MessageBox.Show( "Really?", "Quit?", MessageBoxButtons.OKCancel ) != DialogResult.OK )
        args.Cancel = true;
};
In this context (simple examples) there's very little difference (especially since they apparently compile to nearly identical code) other than brevity. One thing I've found is that my event handlers and EventArgs derivatives tend to have really long names - the brevity of the lambda syntax is very appealing from that standpoint.
Syndicate content