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