Entity Framework 4.0
With .net 4.0 comes Entity Framework 4.0 which will help with data access and rapid development of database projects!
(Don’t worry if you’ve only seen one version of EF before now, this is only the second release).
A while back now in PDC was the session with Shyam Pather and Chris Anderson demoing new features of Entity Framework 4.0 and how it evolved from feedback from the previous EF (I think mentioned as EF 3.5 launched with .Net 3.5).
https://microsoftpdc.com/Sessions/FT10
There are a few great features in the new version including Lazy Loading of entity tracked objects in comparison to using the .Include or .Load methods in order to access your entities, using POCO or Plain Old Clr Objects to enable you to pass objects between tiers easier.
The ability to generate a database structure from the model (where before it was only possible to generate a model from the database), so there is a nice 2 way communication to start the project either from database oriented in which you would generate the EF Model from the database structure, or now if you have your conceptual object/entity model, you can generate database structure from that.
Another great feature is adding the ability to call stored procedures from code without as much overhead as before.
New Features List:
|
|
Lazy Loading
Simply put, with your auto generated classes from EF, you used to have to say .Load() or .Include(“type here”) in code to ensure that the object trees would load… this could be quite frustrating at times especially with complex object graphs.
For example, if we have a Session with many Speakers, and one Speaker can have many Sessions, if we wanted to list all Speakers with Sessions if we were doing it with EF3.5 we would have to write something along the lines of:
using (var context = new Model1Container())
{
foreach (var speaker in context.Speakers.Include("Sessions"))
{
Console.WriteLine(speaker.Name);
// alternatively to the include we could do
// speaker.Sessions.Load();
foreach (var session in speaker.Sessions)
{
Console.WriteLine("\t giving {0} at {1}", session.Title, session.Time);
}
}
}
and if you forgot the Load or Include, you would get exceptions at runtime.
Now you can just leave that out, and as long as the objects are generated or the objects (if defined yourself) have the lazy loading enabled.
To enable this in your own objects there are a couple of steps to do:
Firstly set all navigation properties to be virtual to allow the EF to override them with ones which know how to lazy load.
Secondly in the constructor of the container or context (extending ObjectContext) set ContextOptions.LazyLoadingEnabled = true;
public Model1Container()
: base("name=Model1Container")
{
ContextOptions.LazyLoadingEnabled = true;
}
and the Entity Framework will now allow you to lazy load your objects.
There will be a T4 code generation template (as demonstrated from 13:10 on the PDC video, link at the top of this post), but is not currently shipped with the beta of VS2010.
Calling to the Database
From 29:00 in the link at the top of this blog, explains how to utilize the power of SQL within the Entity Framework. This explains that the improvements on .net 4.0 over .net 3.5 for the SQL queries generated.
From 31:46 shows how to pass a SQL Query to the Database Server as a pipe to the Database. I can see this working very well when calling stored procedures which may not return specific entities or object graphs rather than writing heaps of SQL in your code, and a far better practice.
This goodness can be accessed directly from the context in a method called ExecuteStoreQuery<T>, which takes a type as a generic to format the output as, and a string as the SQL to execute.
Simple Example:
class Program
{
static void Main(string[] args)
{
using (var context = new Model1Container())
{
// the sql to execute
// also formatting it to fit in the Result object type
var sql = @"
select object_id as Id, Name
from sys.objects";
foreach (Result r in context.ExecuteStoreQuery<Result>(sql))
{
Console.WriteLine("{0}: {1}", r.Id, r.Name);
}
}
}
}
// the object formatted result to come back from the DB
public class Result
{
public int Id { get; set; }
public string Name { get; set; }
}
by formatting the results as a strong type, we get intellisense when using the results.
To call stored procedures we have to do a couple of things within our model:
First if the model doesn’t know about the stored procedure, go to the model designer right-click on some whitespace and select “Update Model from Database”, then add the stored procedure as you would with entities.
next we do a function import (right click the whitespace in the model designer again, click Add –> Function Import)
select the stored procedure from the dropdown list, if the type being returned is already an entity, then you can select which entity it returns. Otherwise we can create a new complex type by doing an analyze on the database (push Get Column Information button) and entity framework will create that complex type for you.
In the code we can change the call directly to the method we just imported:
Old:
foreach (Result r in context.ExecuteStoreQuery<Result>(sql))
New:
foreach (var r in context.ExactSameThing())
// or whatever your sproc is called from the function import
Overriding SaveChanges
As the SaveChanges method is now virtual, so it is possible to do checking and access the ObjectStateManager for validation. (this is explained from 21:20 in the link at the top of this blog).
The example given to demonstrate this is to throw an InvalidOperationException if there is more than 1 entity added… a bit of a silly example but goes to show the power of this.
public partial class Model1Container
{
public override int SaveChanges(SaveOptions options)
{
if (ObjectStateManager.GetObjectStateEntries(
EntityState.Added).Count() > 1)
{
throw new InvalidOperationException("Simple demo code... don't use in production");
}
return base.SaveChanges(options);
}
}
Remember here to put this inside the class with the same name as your context as a partial class to allow you to override.