Feature CTP Walkthrough: Code Only for the Entity Framework

Published 22 June 09 02:54 PM | dpblogs 

Code Only Walkthru:

1) Create a Console Application called "CodeOnlyWalkthru":

blog1

2) Add a new Project to the "CodeOnlyWalkThru" solution:

blog1

3) Choose 'Class Library' and call the library "Entities":

blog1

 

4) Add a "Category" class to your Entities project:

Right click on the Entities project and add a class called "Category" then past this code into the class:

public class Category
{
private List<Product> _products;
public int ID { get; set; }
public string Name { get; set; }
public virtual List<Product> Products {
get
{
if (_products == null)
_products = new List<Product>();
return _products;
}
set
{
_products = value;
}
}
}

 

5) Generate the "Product" class:

Inside the "Category.cs" class right click on a reference to the non-existent Product class and choose "Generate > Class" from the context menu:

blog1

In the new Product class paste this code:

public class Product
{
public int ID { get; set; }
public string Name { get; set; }
}

Your project should now look like this:

blog1

We are keeping these entity classes in a separate project so they are compiled into an assembly that has no dependencies on the Entity Framework. The Entities assembly is therefore persistence ignorant, which is very important for some developers. The persistence aware code lives in a separate assembly which references the persistence ignorant assembly.

6) In the "CodeOnlyWalkThru" Project add a reference to the Entities Project:

blog1

7) In the "CodeOnlyWalkThru" project add a reference to "System.Data.Entity" and "Microsoft.Data.Entity.Ctp":

blog1

image

NOTE: In the long run we plan on merging the Code Only functionality into the core Entity Framework assembly. When we get to this work you would only need the first reference.

8) In the "CodeOnlyWalkThru" project add a new class called "ProductDBContext":

 

blog1

9) Put this code in the "ProductDBContext" class:

public class ProductDBContext: ObjectContext
{
public ProductDBContext(EntityConnection connection)
: base(connection, "ProductDBContext")
{
ContextOptions.DeferredLoadingEnabled = true;
}
public IObjectSet<Category> Categories
{
get { return CreateObjectSet<Category>(); }
}
public IObjectSet<Product> Products
{
get { return CreateObjectSet<Product>(); }
}
}

Since this class extends ObjectContext, it represents the shape of your model and acts as the gateway to your database. Notice that we create ObjectSets for both of our entity types. We also add a constructor that takes an EntityConnection, the ContextBuilder will fabricate an EntityConnection, which is a wrapper around the real database connection and the Entity Framework metadata, and pass it to this constructor when we ask it to create a new instance of our ProductDBContext. In the constructor we also configure the Entity Framework to enable DeferredLoading (aka LazyLoading).

10) Now write paste this code into your "Program" class:

SqlConnection connection = new SqlConnection(@"Data Source=.\SQLEXPRESS;Initial Catalog=ProductDB;Integrated Security=SSPI;");
using (ProductDBContext context = ContextBuilder.Create<ProductDBContext>(connection))
{
if (!context.DatabaseExists())
context.CreateDatabase();
Category food = new Category { CID = 1, Name = "Food" };
Product bovril = new Product { ID = 1, Name = "Bovril" };
Product marmite = new Product { ID = 2, Name = "Marmite" };
Product vegemite = new Product { ID = 3, Name = "Vegemite" };
food.Products.Add(bovril);
food.Products.Add(marmite);
food.Products.Add(vegemite);
context.Categories.AddObject(food);
context.SaveChanges();
// Query the database
food = context.Categories.Single();
foreach (var product in food.Products)
Console.WriteLine(product.Name);
}

 

This code creates a context completely by convention, that connects to the ProductDB database on the local SQLExpress installation. If the ProductDB database doesn’t exist it will create it.

Finally once you have a context up and running you use it just like you normally would, in this case we create a Category and 3 Products related to each other, and then we retrieve the Category again from the database and use LazyLoading (aka DeferredLoading) to loop over its products

It is that easy.

11) Configure the ContextBuilder

So far we have done everything by convention because Code Only could infer everything by convention. If however we change the Category class so it looks like this:

public class Category
{
private List<Product> _products;
public int CID { get; set; }
public string Name { get; set; }
public virtual List<Product> Products {
get
{
if (_products == null)
_products = new List<Product>();
return _products;
}
set
{
_products = value;
}
}
}

CodeOnly doesn't know that CID is the key*. This means you have to create an instance of a ContextBuilder and use it to register CID as the key, like this:

var builder = new ContextBuilder<ProductDBContext>();
builder.RegisterKey((Category c) => c.CID);

You can Register many keys on the same builder if necessary. Once you have done configuring your builder, you can create an instance of the ProductDBContext using the Create method:

using (ProductDBContext context = builder.Create(connection))

 

The rest of the code is unchanged.

You should generally re-use your configured ContextBuilder whenever you need to create an ObjectContext, rather than re-configuring each time, as this will help with performance. The best way to do this is probably via a static variable somewhere.

*By convention any property called ID, Id, ClassNameID or ClassNameId is assumed to be the entity key. If a property with one of these names can't be found then you have to call RegisterKey() to tell the entity framework which property is a key.

Known Limitations of Code Only in the Feature CTP for Beta1

This release is a very early preview of Code Only, and as such has a number of known limitations, that we plan on addressing in subsequent releases, including:

  • ComplexTypes are not supported.
  • Configurable Mapping is not supported.
  • Table per Hierarchy is the only inheritance strategy supported.
  • Specifying Facets is not supported, so for example you can't specify the max length of a string column in the database. Instead defaults are used.
  • There is no Provider Model, so CodeOnly only supports SqlServer at this point.
  • CodeOnly provides no way to specify which properties participate in the same relationship but are simply the inverse of each other. So for example if you added a Category property to the Product class used in the example above the result would be 2 relationships between Product & Category, and consequently 2 FKs in the Products table, because the Entity Framework can't infer that Product.Category and Category.Products are simply the inverse of each other.
  • ManyToMany relationships are not supported.

- Alex James
  Program Manager, Entity Framework

Filed under:
Attachment(s): CodeOnlyWalkthru.zip

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

# Entity Framework CTP with Code Only &ndash; Now Available &laquo; Framework Madness! said on June 22, 2009 7:59 PM:

PingBack from http://leriksen71.wordpress.com/2009/06/22/entity-framework-ctp-with-code-only-now-available/

# Mikael Henriksson said on June 23, 2009 6:17 AM:

Finally! Huge step in the right direction. This is ultimately what I have wished for x-mas the last couple of years. I suppose I will miss the mappings, hierarchy and complex types but hey. You will be able to make that for the release version right?

# Ryan Riley said on June 24, 2009 10:19 AM:

I agree with Mikael; this is a very nice step forward.

# Mauricio Rodriguez said on June 25, 2009 12:46 AM:

How testable is the code only approch?????

# Jack said on June 26, 2009 2:41 AM:

Very great! It will surely save us lots of time!

# Marcelo said on June 28, 2009 3:19 AM:

Hi

Please, can add a complete sample using a generic repository and unit of work. The actual sample it is not generic.

A good sample help to learn!

# emanuele said on June 29, 2009 7:04 AM:

Very interesting.

When did you planned to release the beta version?

# Eric Hexter said on July 12, 2009 11:42 AM:

I am not sure I like having to specifiy the DefaultContainerName in the ObjectContext.  I walked through this sample with my own object model and it seemed that their is some some coupling to the name of my ObjectContext class. If so, why can't the framework infer the name and let me go on?  

I am excited to see more about this feature!

# cowgaR said on July 14, 2009 9:35 AM:

great work, reminds NHibernate with fluent mappings more and more...but couple of questions:

1. why is the "connection" passed in constructor in the Context, when all the other ORMs have it in some kind of Factory, e.g. ContextBuilder here (I'm entity framework newbie).

The factory then builds the "sessions"/"uow" e.g. Contexts in this case with this information, the other ORMs are trying to keep the session as lightweight as possible (as usually you will be creating Context per request in web apps).

2. in your Category class you should probably instantiate _products collection in a constructor,

it is much clearer solution (also found all around the web).

3. Where can I define identity strategy for the (primary) key? e.g. GUID COMB and so on?

4. Why do you need provider model? Haven't looked deeply on Entity Framework but it smells like the bad design for me. Shouldn't you reuse the providers already built in and push code-only-model (or transfer it) to an established designer model, which of course understands providers (so If I am using say sqlite one it works out of the box). Just I don't get it, when I can create table/update schema/change relationships using designer on say Oracle database, why can't I just do it with code-only, which should just be another layer.

5. I hope the listed limitation will be addressed, as they are really the barebone of what is needed, nice project for you to look at (which is much further in this) is

http://fluentnhibernate.org/

started by Mr. Gregory, and in many points it has even nicer design.

As I haven't been followint EF some questions may sound silly, but code-only approach surprised me so definitely going to play with it. Good luck, finaly the right way to do an ORM!

# Eric Hexter said on July 14, 2009 10:03 AM:

After going through the walkthrough my biggest complaint with the current bits is that the foreign key is only generated when I expose a List<foo> as a public virtual property. I would much rather create somthing like this and have EF access a private or protected member of my class:

   public class UserGroup

   {

       private List<Conference> _conference=new List<Conference>();

       public virtual  void AddConference(Conference conference)

       {

           _conference.Add(conference);

       }

       public virtual Conference[] GetAllConferences()

       {

           return _conference.ToArray();

       }

}

This way my domain object can apply rules around how conferences are removed from my UserGroup object.

This code is part of the CodeCampServer.org project that I am testing the CodeOnly features against.

# Damien Guard said on August 7, 2009 2:08 AM:

@cowgaR:

1. Not in scope for this project.

2. Personal style choice, not enforced.

3. Coming in next CTP.

4. Because the existing provider model does not support DDL for create/drop/exists database. If you don't need those then it could run with an existing provider.

5. We have more stuff coming.

[)amien

# progame said on August 24, 2009 6:40 AM:

hope to support full custom mapping for entityset info just like IQToolKit,

so i can support partial fields loading and different name convidence mapping.

Leave a Comment

(required) 
(optional)
(required) 

  
Enter Code Here: Required

Search

This Blog

Syndication

Page view tracker