Entity Framework 4 Persistence-Ignorance First Look

by mosessaur| 20 May 2009| 5 Comments

Introduction:

From the moment I put my hands on Visual Studio.Net 2010 Beta 1 and I’m targeting EF4 –Entity Framework 4- as I was very excited to checkout the new cool feature of it.

Here I am going to highlight my first look at Persistence-Ignorance support in EF4.

EF4 Support for POCO classes:

Well, what I can say?! it as simple as writing something like this:

public class Category
{
    public int CategoryID { get; set; }
    public string CategoryName { get; set; }
    public string Description { get; set; }
    public ICollection<Product> Products { get; private set; }
}

The above code is your POCO class. The class name exactly matches the Entity Type in CSDL and so all the properties.

So what about ObjectContext?! I implemented my own simple one for demonstration:

public class NorthwindObjectContext : ObjectContext
{
    public NorthwindObjectContext(string connectionString)
        : base(connectionString, "NorthwindContext")
    {
    }

    private IObjectSet<Category> _categorySet;

    public IObjectSet<Category> CategorySet 
    {
        get 
        {
            if (_categorySet == null)
            {
                _categorySet = CreateObjectSet<Category>();
            }
            return _categorySet;
        }
    }
}

On a simple console application I made the following.
public static void Main(string[] args)
{
 using (var context = new NorthwindObjectContext("name=NorthwindContext"))
 {
	try
	{
		var category = context.CategorySet.First();
		Console.WriteLine(category.CategoryName);
	}
	catch (Exception ex)
	{
		Console.Write(ex.ToString());
	}
 }
}

And to checkout also that it supports Compiled Queries I made one

private readonly static Func<NorthwindObjectContext, int, Category> FindCategoryById = 
            CompiledQuery.Compile<NorthwindObjectContext, int, Category>(
            (db,id) => db.CategorySet.SingleOrDefault(c=>c.CategoryID==id));

And the run it

var category = FindCategoryById.Invoke(context,2);
Console.WriteLine(category.CategoryName);

And that was great for a first touch. It became more easier.

About Change Tracking & Deferred Loading:

One important thing I must clarify about my POCO class above (the Category class). This class doesn’t support change tracking or transparent deferred loading (lazy loading). So for example if you tried to get Products property of Category class, it will return null.

And if you modified the category instance and just call context.SaveChanges(true); this will have no effect because the category instance is already not tracked for any change.

Of course these is a reason of that. The reason is stated on the requirement of Persistence-Ignorant Objects on MSDN to enable POCO classes to support self-change tracking as well as deferred loading. Here is what MSDN states:

Class Definition Requirements

To be able to generate the proxy objects that are required by Object Services to track changes and to support deferred loading of related objects, custom data classes must meet the following requirements. (read more about class POCO class definition requirements in EF4)

So for this sample I will not implement these requirements (keep tuned for next posts) But I will show how to explicitly load related objects and submit changes.

Explicit loading of related objects using newly introduced method LoadProperty:

private static void FetchSample()
{
 	using (var context = new NorthwindObjectContext("name=NorthwindContext"))
 	{
		try
		{
			//By default it is false
			context.ContextOptions.DeferredLoadingEnabled = true;
        
			//using compiled queries
			var category = FindCategoryById.Invoke(context, 2);

			//Explicit Loading of Products
			context.LoadProperty<Category>(category, c => c.Products);
			Console.WriteLine("{0} has {1} products", 
													category.CategoryName, 
													category.Products.Count);

			category = context.CategorySet.First();
			Console.WriteLine(category.CategoryName);
		}
		catch (Exception ex)
		{
			Console.Write(ex.ToString());
		}
	}
}

And for submitting changes:

private static void UpdateSample()
{
	using (var context = new NorthwindObjectContext("name=NorthwindContext"))
	{
		try
		{
			context.ContextOptions.ProxyCreationEnabled = true;
			var category = FindCategoryById.Invoke(context, 1); //context.CategorySet.First();
            
			Console.WriteLine("{0}:{1}",category.CategoryName, category.Description);
			category.Description = category.Description + "[Updated]";
            
			//No generated proxy classes => No tracking
			//Call DetectChanges(); Explicitly
			//Ref: http://msdn.microsoft.com/en-us/library/dd456848(VS.100).aspx
			context.DetectChanges();    
			context.SaveChanges();
			Console.WriteLine("{0}:{1}", category.CategoryName, category.Description);
		}
		catch (Exception ex)
		{
			Console.Write(ex.ToString());
		}
	}
}

At line 16 I am calling DetectChanges method. There is an alternate way which is to call SaveChanges(SaveOptions) and supply a value of DetectChangesBeforeSave. In this case DetectChanges is automatically called before changes are persisted to the data source.

Conclusion:

EF4 is really far away of EF v1. Totally brand new product. It will beat the popularity LINQ to SQL had earlier especially after all new added features to it.

I will blog soon about deferred loading and change tracking with EF4 after applying POCO class definition requirements.

Download the sample (requires VS.Net 2010 Beta 1)

NOTE: The sample is using Northwind database which is not attached. You can download it from Microsoft web site

MSDN References:

ADO.NET Team Blog

Comments (5) -

Sergejus
Sergejus Lithuania on 5/19/2009 6:54 AM Why are you not just using virtual on the properties for the change tracking?
mosessaur
mosessaur Egypt on 5/19/2009 7:10 AM Yeah I could, but from design point of view and in real life you might not want to do so! But no harm of course.
I just wanted to hit about in details.
Appearantly it seems doing virtuals and following guidlines would improve the performance.
social.msdn.microsoft.com/.../52d8d8e6-7f50-4968-b182-2453bbd97c42
Sergejus
Sergejus Lithuania on 5/23/2009 4:20 PM What's your concern about using virtual on properties from the design perspective?
mosessaur
mosessaur Egypt on 5/24/2009 10:52 PM Why I would expose methods as virtuals while they shouldn't be overriden by any referenced code?!
By design I should decide which properties/methods that should be exposed to public and which not in order not to violate system usage.
However in EF4 POCO cases, I guess it would be acceptable. However we should know pros and cons of each approach. And be able to implement them effeciently.
Sergejus
Sergejus Lithuania on 5/27/2009 7:08 AM For the last year, I'm making 70% of my non-helper methods virtual. Java has all methods virtual by default, so personally I don't think it's a big issue (at least for me Smile).

Pingbacks and trackbacks (3)+

Comments are closed