One of the main features of the Entity Framework revolves around Object Services. The main points of Object services are to write less code and allow programmers to program against objects to access the data that’s stored in a database or possibly anywhere. We can consider this feature as a road to CRUD; where CRUD represents Create, Read, Update, and Delete operations against data, except this feature provides more than just a simple road.

How this works?

Object Services is the top layer in the Entity Framework. The framework consists of three district layers: EDM, mapping, and the source layer. The important layer for Object Services is the EDM layer (also label CSDL). The Entity Data Model (EDM) layer brings the concepts of entities to stored data. Currently in version 1.0 of the ADO.NET Entity Framework there is a 1:1 relationship between the EDM and Objects Services. Object Services is the realization of Objects from those described Entities. The table below shows the different layers.

Another important feature for Object Services and the Entity Framework in general comes with the knowledge that the Objects Services gives access to the entity type information in the lower layers of the Framework. By providing access to the lower layers of the Entity Framework, customers gain access to specific type information, relationship information, and basic data readers and writers to the data. One particular scenario may be translating between data sources, and one way to do this would be to gain access to the type information.

What can you do with Object Services?

Here’s a bullet list of some of the normal operations which object services can provide:

·         Query using LINQ or Entity SQL

·         CRUD

·         State Management – change tracking with events

·         Lazy loading

·         Inheritance

·         Navigating relationships

More features of Object Services allow for data conflicts resolution. For example, Object Services supports:

·         Optimistic concurrency

·         Identity resolution -  keeping on copy of the object even from several different queries

·         Merging

·         Refreshing data with overwrite options (ie: server wins or client wins)

These are important concepts to understand because the Entity Framework isn’t just designed to do CRUD operations; the Entity Framework is designed to scale to large or even mission critical applications. Given a large or small program, programming against a service model with consistent error handling, data handling, and easy access to data layers allow programs to have a robust experience. These features also allow programmers to work on features instead of core application plumbing.

Let’s dive into some examples:

Here’s a simple sample using a query with Entity SQL that does a foreach over objects materialized from the EDM.

    using (NorthwindEntities northWind = new NorthwindEntities())

    {

        // Calling CreateQuery materializes objects

        ObjectQuery<Products> products =

            northWind.CreateQuery<Products>(

                "SELECT VALUE p FROM Products AS p");

        foreach (Products p in products)

        {

            Console.WriteLine(p.ProductName);

        } // foreach

    }   // using Northwind Entities

 

Same sample using LINQ.

    using (NorthwindEntities northWind = new NorthwindEntities())

    {

        var products = from p in northWind.Products select p;

        foreach (Products product in products)

        {

            Console.WriteLine(product.ProductName);

        }   // for each

    }   // using

CRUD Examples:

The next example does a LINQ query retrieving all the products that belong to a category called beverages and then just for kicks, changes the discontinued products that have unit prices to $1.25.  When looking at the samples,  notice that there’s a call to save changes which only pushes the modified Objects back to the the data source.

    using (NorthwindEntities northWind = new NorthwindEntities())

    {

        // do a LINQ query which finds all the products that fall

        // under the category beverages

        var products = from p in northWind.Products

                       where p.Categories.CategoryName == "beverages"

                       select p;

 

        foreach (Products product in products)

        {

            // with lazy loading, object references must

            // be loaded first, otherwise an exception is thrown.

            // this allows for a reduced number of trips to the source.

            Console.WriteLine("{0}\tDiscontinued: {1}",

                                product.ProductName,

                                product.Discontinued);

           

            // just for fun, if the product is discontinued,

            // then let's set the unit price to $1.25

            if (product.Discontinued)

            {

                product.UnitPrice = (decimal)1.25;

            }   // if           

        }   // for each

 

        // notice, that until we call save changes

        // the data in the database or source is not updated.

        northWind.SaveChanges();

    }   // using

One more example with conflict:

The final example is a little longer, but shows optimistic concurrency and one way to deal with the conflict. conflicts. Also note that to make this work, which also shows the flexibility in the EDM, the entity set Categories must have an attribute flagged with ConcurrencyMode set to “fixed”.

// Property set in the EDM or CSDL file.

<ProperyName = “CategoryName” …(other attributes) ConcurrencyMode=”fixed”/>

 

Code example:

    // save the category id out for retrieval later in this example.

    int cateID = 0;

 

    // create an instances of a new category and add to the list

    // of categories.

    using (NorthwindEntities northWind = new NorthwindEntities())

    {

        // create a new category

        Categories catNew = new Categories();

        catNew.CategoryName = "Blog Example";

        catNew.Description = "Blog description";

 

        // add to object context, and save changes

        northWind.AddObject(catNew);

        northWind.SaveChanges();

 

        // cache away the category ID.

        cateID = catNew.CategoryID;

    } // using

 

    // create different object context variables

    using (NorthwindEntities northWind1 = new NorthwindEntities())

    using (NorthwindEntities northWind2 = new NorthwindEntities())

    {

        // using a direct query from the categories item from

        // northwind 2, get the id out.

        Categories cat1 = northWind1.CreateQuery<Categories>(

           "SELECT VALUE c FROM Categories AS c WHERE c.CategoryID=@id",

           new ObjectParameter("id", cateID)).First();

        cat1.CategoryName = "category 1";

 

        // using a direct query from the categories item from

        // northwind 2, get the id out.

        Categories cat2 = northWind2.CreateQuery<Categories>(

            "SELECT VALUE c FROM Categories AS c WHERE c.CategoryID=@id",

            new ObjectParameter("id", cateID)).First();

        cat2.CategoryName = "category 2";

       

        // save northwind 2 so we can create a conflict.

        northWind2.SaveChanges();

 

        try

        {

            // with the second save changes, the services notices the data

            // that’s out of sync and throws an exception.

            northWind1.SaveChanges();

        }   // try  

        catch(OptimisticConcurrencyException)

        {

            Console.WriteLine("Caught optimistic concurrency exception");

           

        }   // catch

 

        // One way of fixing the violation is to

        // refresh the first object context, then

        // change the category name again

        // and save changes.

        northWind1.Refresh(RefreshMode.StoreWins, cat1);

        cat1.CategoryName = "category 1";

        northWind1.SaveChanges();

 

        // for the sake of our database, let's delete the

        // object, and not to forget to refresh

        // and save changes

        northWind2.Refresh(RefreshMode.StoreWins, cat2);

        northWind2.DeleteObject(cat2);

        northWind2.SaveChanges();

    } // using

 

To Sum it up:

This briefly describes the Object Services layer of the Entity Framework. There is a lot more, but the basic concepts are: writing less code and get more powerful services.

Watch for more blogs to detail the subject of Object Services in the near future.

 

Brian Dawson

ADO.NET Program Manager