POCO in the Entity Framework: Part 1 - The Experience

Published 21 May 09 05:46 PM | dpblogs 

Last week I mentioned in the sneak preview on POCO that support for POCO entities is one of the new capabilities we have added to Entity Framework 4.0. This week, I’d like to go into the details of POCO support in Entity Framework 4.0.

There’s quite a bit to discuss here, including:

  • Overall POCO experience in Entity Framework 4.0
  • Change Tracking in POCO
  • Relationship Fix-up
  • Complex Types
  • Deferred (Lazy) Loading and Explicit Loading
  • Best Practices

In this post, I will focus primarily on the overall experience so that you can get started with POCO in Entity Framework 4.0 right away. I’d like to use a simple example that we can walk through so you can see what it feels like to use POCO in Entity Framework 4.0. I will use the Northwind database, and  we’ll continue to build on this example in subsequent posts.

Step 1 – Create the Model, turn off default Code Generation

While POCO allows you to write your own entity classes in a persistence ignorant fashion, there is still the need for you to “plug in” persistence and EF metadata so that your POCO entities can be materialized from the database and persisted back to the database. In order to do this, you will still need to either create an Entity Data Model using the Entity Framework Designer or provide the CSDL, SSDL and MSL metadata files exactly as you have done with Entity Framework 3.5. So first I’ll generate an EDMX using the ADO.NET Entity Data Model Wizard.

image

  1. Create a class library project for defining your POCO types. I named mine NorthwindModel. This project will be persistence ignorant and will not have a dependency on the Entity Framework.
  2. Create a class library project that will contain your persistence aware code. I named mine NorthwindData. This project will have a dependency on Entity Framework (System.Data.Entity) in addition to a dependency on the NorthwindModel project.
  3. Add New Item to the NorthwindData project and add an ADO.NET Entity Data Model called Northwind.edmx (doing this will automatically add the dependency to the Entity Framework).
  4. Go through “Generate from Database” and build a model for the Northwind database.
  5. For now, select Categories and Products as the only two tables you are interested in adding to your Entity Data model.

Now that I have my Entity Data model to work with, there is one final step before I start to write code : turn off code generation. After all you are interested in POCO – so remove the Custom Tool that is responsible for generating EntityObject based code for Northwind.edmx. This will turn off code generation for your model.

image

We are now ready to write our POCO entities.

Step 2 – Code up your POCO entities

I am going to write simple POCO entities for Category and Product. These will be added to the NorthwindModel project. Note that what I show here shouldn’t be taken as best practice and the intention here is to demonstrate the simplest case that works out of the box. We will extend and customize this to our needs as we go forward and build on top of this using Repository and Unit of Work patterns later on.

Here’s sample code for our Category entity:

    public class Category
    {
        public int CategoryID { get; set; }
        public string CategoryName { get; set; }
        public string Description { get; set; }
        public byte[] Picture { get; set; }
        public List<Product> Products { get; set; }
    }

Note that I have defined properties for scalar properties as well as navigation properties in my model. The Navigation Property in our model translates to a List<Product>.

Similarly, Product entity can be coded like this:

    public class Product
    {
        public int ProductID { get; set; }
        public string ProductName { get; set; }
        public int SupplierID { get; set; }
        public string QuantityPerUnit { get; set; }
        public decimal UnitPrice { get; set; }
        public Int16 UnitsInStock { get; set; }
        public Int16 UnitsOnOrder { get; set; }
        public Int16 ReorderLevel { get; set; }
        public bool Discontinued { get; set; }
        public Category Category { get; set; }
    }

In this case, since the relationship allows only one Category that a Product can belong to, we have a reference to a Category (unlike the List<T> collection we have for modeling the Navigation Property in Category).

Step 3 – Code up your Entity Framework Context

The last thing I have to do in order to pull all of this together is to provide a context implementation (much like the ObjectContext implementation you get when you use default code generation). The context is the glue that brings persistence awareness into your application, and it will allow you to compose queries, materialize entities as well as save changes back to the database. The context will be a part of the NorthwindData project.

For simplicity, I will include our context into the same class library that has our entity types – but when we discuss patterns such as Repository and Unit of Work, we will set it up such that you have a pure POCO class library without any persistence concerns.

Here’s a simple context implementation for our scenario:

public class NorthwindContext : ObjectContext
    {   
        public NorthwindContext() : base("name=NorthwindEntities", 
"NorthwindEntities") { _categories = CreateObjectSet<Category>(); _products = CreateObjectSet<Product>(); } public ObjectSet<Category> Categories { get { return _categories; } } private ObjectSet<Category> _categories; public ObjectSet<Product> Products { get { return _products; } } private ObjectSet<Product> _products; }

Note that ObjectSet<T> is a more specialized ObjectQuery<T> that we introduced in Entity Framework 4.0.

That’s it – now you have pure POCO entities with a simple context that will allow you to write queries like this:

    NorthwindContext db = new NorthwindContext();

    var beverages = from p in db.Products
                    where p.Category.CategoryName == "Beverages"
                    select p;

The entities that are materialized are pure POCO entities, and you can make and persist changes much like you would with regular EntityObject or IPOCO entities. You get all the services provided by Entity Framework - the only difference is that you are using pure POCO entities.

There are many possibilities here as far as how we can improve on this simplified example. Before we get into that however, I would like to get some basic questions out of the way.

Do I need an Entity Data Model before I can use POCO?

Yes – POCO support in Entity Framework 4.0 simply removes the need of having persistence specific concerns in your entity classes. There is still the need for you to have a CSDL/SSDL/MSL (collectively EDMX) metadata so that the Entity Framework is able to use your entities along with the metadata in order to enable data access. There is a separate effort that we are working on that will allow you to do true “code-first” development without the need to have a predefined EDMX model. A community preview of this feature will be released to the web in the coming months. We will roll this into the product the first chance we get. As always, your feedback will be helpful.

Do I have to always hand-craft these entities and the context?

No – there is a very powerful and flexible code generation mechanism in Entity Framework 4.0 that is based on T4 as Alex blogged about here. You can provide your own templates that allow you to build your entities in a way that you see fit. We are also working on providing standard out of the box templates that will generate POCO entities for you.

How is metadata mapped when using POCO entities?

In Entity Framework 3.5, both EntityObject and IPOCO based entities relied on the use of mapping attributes that were meant for decorating and mapping the entity types and properties back to the corresponding elements in the Conceptual model. Entity Framework 4.0 introduces convention based mapping for allowing mapping of Entity Types, Properties, Complex Types and Relationships back to the conceptual model without the need for explicit decoration. The simple rule here is that Entity Type names, Property names and Complex Types names used in your POCO classes must match those defined by the conceptual model. Namespace names are ignored and don’t have to match between the class definition and the conceptual model.

Do I need to have public getters and setters for all properties in my entity classes?

You can use any access modifier on your POCO type’s properties as long as none of the mapped properties are virtual and as long as you don’t require partial trust support. When running in partial trust, there are specific requirements on the visibility of access modifiers on your entity classes. We will be documenting the complete set of access modifiers that are supported when partial trust is involved.

What types of collections are supported for collection based navigation properties?

Any collection that is an ICollection<T> will be supported. If you don’t initialize the field with a concrete type that is an ICollection<T> type, then an List<T> type will be provided upon materialization.

Can I have uni-directional relationships? For instance – I would like to have a Category property in my Product class, but I don’t want to have a Products collection in my Category class.

Yes – this is supported. The only restriction here is that your entity types have to reflect what is defined by the model. If you are not interested in having the navigation property for one side of the relationship, then remove it from the model completely.

Is Deferred (Lazy) Loading supported with POCO?

Yes – Deferred (Lazy) loading is supported with POCO through the use of proxy types that are used to provide automatic lazy loading behavior on top of your POCO classes. This is something that we’ll cover when we get to deferred loading – until then know that eager loading via the use of “Include” is also supported, like so:

var beverageCategory = (from c in context.Categories
.Include("Products") where c.CategoryName == "Beverages" select c).Single();

If I were to use Deferred (Lazy) Loading, I don’t have to do this – we’ll discuss that when we discuss proxies.

Fixing up Relationships

There are two types of fix-ups to be aware of: 1)Fix-up during query, and 2) Fix-up during changes to your entities/relationships

Fix-up during Query

Fix-up during query happens when you load related entities using separate queries on the same ObjectContext. For instance, if I were to query for a category instance Beverages, and later query for a product instance Chai (that is in Category Beverages), I would want chai.Category to point to the instance of the Beverages category without additional work.

This is automatic and works today.

Fix-up during changes to your entities/relationships

This is the relationship fix-up between two entities when I add/remove an entity that is related to another entity or alter relationships. Think of this as the case when I create a new product called “Diet Chai” and want to associate it with the Beverages category.

In Beta1 of Entity Framework 4.0, you do not get automatic relationship fix-up in this case with POCO entities. When dealing with relationships that change between entities, you will have to make sure that your POCO types include the logic to manage fix-up on both ends of the relationship correctly.

For instance, in my Northwind example, I have defined the following method on Category to support adding / removing of Orders.

        public void AddProduct(Product p)
        {
            if (Products == null)
            {
                Products = new List<Product>();
            }

            if (!Products.Contains(p))
            {
                Products.Add(p);
            }            
            
            p.Category = this;
        }

In general, it is good to use a pattern like this to support adding/removing related items rather than using the relationship collection to add/remove related entities. You also have options of making the getter/setter for the actual EF backed collection private/internal to support more fine grained access – but as mentioned earlier, some of this depends on the requirements as to whether you require partial trust support or not.

So we have covered quite a bit of ground in this “quick look” at the overall POCO experience. There’s quite a lot more to talk about – and I will be continuing this discussion early next week. In the meantime, take a look at the complete solution (attached) if you are interested in the sample code covering all the concepts we covered here. Please keep in mind that you must have a local instance of Northwind database installed on the machine where you are running this sample.

In my next post we will look at Complex Types, Change Tracking, Proxies, Lazy Loading and Eager Loading. Until then, please look through the MSDN Documentation on POCO here for more details on POCO support in Entity Framework 4.0.

Let us know what you think!

Faisal Mohamood
Program Manager, Entity Framework

Filed under:

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

# POCO in the Entity Framework: Part 1 - The Experience | ASP NET Hosting said on May 21, 2009 9:01 PM:

PingBack from http://asp-net-hosting.simplynetdev.com/poco-in-the-entity-framework-part-1-the-experience/

# hans said on May 21, 2009 10:41 PM:

In LINQ, it has a CreateDatabase() method where I can create the database based on the POCO.

Does EntityFramework have that kind of method?

# dmitry said on May 22, 2009 12:55 AM:

Is there a way to use "HashSet<Product> Products" instead of "List<Product> Products" in the Category POCO?

# progg.ru said on May 22, 2009 1:02 AM:

Thank you for submitting this cool story - Trackback from progg.ru

# Matt said on May 22, 2009 3:47 AM:

@dmitry: HashSet<T> should work as it implements ICollection<T>.

# 9eFish said on May 22, 2009 4:45 AM:

9efish.感谢你的文章 - Trackback from 9eFish

# Brendan said on May 22, 2009 4:49 AM:

Is partial table mapping supported via the use of defaults defined within the model? e.g:

Table: Id int PK,

          Col1 varchar(250) null,

          Col2 bit not null

I'd create the model to match the above but miss out Col2 and provide a default of null within the SSDL. My POCO would then just have the Id and Col2 properties. Is this possible?

# Brendan said on May 22, 2009 4:55 AM:

I meant Col1 (in my above question) for the POCO property!

# dmitry said on May 22, 2009 9:01 AM:

@Matt, for some reason HashSet/ISet does not work as an automatic property. The exception says something like "unable to to create property x for type y." It does work if you create a backing variable and initialize it.

ICollection/IList and List all work fine with an automatic property.

# Rick said on May 22, 2009 9:54 AM:

Great article.  

Towards the end of the article though, you wrote, "In the meantime, take a look at the complete solution (attached) if you are interested in the sample code covering all the concepts we covered here."  

I don't see a link to the sample code anywhere though.  Can you point me to the location of the sample code download?

Also, can anybody provide any references that show how to use generated entities (EntityObject) that support changes on the entity made after the context has been detached?

Thanks,

Rick

# DotNetShoutout said on May 22, 2009 10:22 AM:

Thank you for submitting this cool story - Trackback from DotNetShoutout

# Muhammad Mosa said on May 22, 2009 11:05 AM:

Nicely done Faisal! well presented and explained.

That was really an addition to existing documentation.

# Faisal said on May 22, 2009 3:28 PM:

Hi Rick,

I have fixed the issue with the attachment not being a part of the post. The post now has an attachment that you can download.

-faisal

# ADO.NET team blog said on May 22, 2009 5:17 PM:

Since we shipped the .NET Framework 3.5 SP1 and Visual Studio 2008, we’ve been working on the next version

# nhibernateuser said on May 24, 2009 8:54 AM:

you are completely missing the point with the "generate from the DB"...

POCO idiom is used in DDD, there is no reason to abstract the framework away with POCO once my goal is to "design" from the DB. And no ability to create the DB from POCO. And the designer is DB diagram not entity/POCO diagram.

fail

# Thanigainathan said on May 24, 2009 10:09 AM:

Hi,

Very nice post Faisal. So you are making it completely persistent one.

Cheers!

Thani

# Savante said on May 25, 2009 9:33 AM:

I don't understand why i have to provide a context implementation. Since I have a diagram definition, the framework must know how make the entity tracking using proxies without define ObjectSet<T>. I think that EF must use more the model definition to manage entities. By the momen, I prefer the NHibernate solution in this way.

# Dmitry said on May 25, 2009 6:46 PM:

@Savante,

I don't think really have to "implement" the context implementation. If you look at the code the sample context does two things.

1. Provides connection and container names into the base ObjectContext object.

2. Caches an instance of the ObjectSet<T> in a public property for each entity type.

There is really nothing model specific in it. Both the issues above could be resolved by implementing a context that works with any EF 4.0 projects.

The derived object would get connection and container data from Web.Config and the mapping metadata and would pass it into the ObjectContext.

It would also implement implement a method (for example) Set<T>() which would initialize and cache in a hashtable an ObjectSet<T> instance for each entity type.

This context could be reused in any application without having to manually implement anything; and you would be able to access entity sets using "context.Set<Category>()".

P.S. I agree with nhibernateuser that it would make more sense to generate designer mappings from the model and not the other way around.

# Code Monkey Labs said on May 26, 2009 11:25 AM:

Pick of the week: IP and Non-Competes for Employees General Visual Studio 2010 Beta 1 : Go get the first beta of the next version of Visual Studio! Microsoft Set To Announce Commercial Availability of Windows Azure at PDC This Year : Alin Irimie has some

# Learnings.. said on May 26, 2009 8:46 PM:

Going through the changes in Entity Framework I must say MSFT really does take in feedback. I have been

# Learnings.. said on May 27, 2009 6:50 PM:

Going through the changes in Entity Framework I must say MSFT really does take in feedback. I have been

# divega@microsoft.com said on May 28, 2009 1:12 AM:

@Brendan,

We don't have plans for supporting partially mapped entity types in this release, but I certainly would like to hear what makes this feature important to you.

-Diego

# Alexey Shirshov said on May 28, 2009 2:48 AM:

What about references in POCO types to general entities and vice versa.

# ADO.NET team blog said on May 28, 2009 12:03 PM:

In my post last week on the POCO Experience in Entity Framework , I covered the fundamentals of POCO

# Hemanshu Bhojak said on May 29, 2009 3:47 PM:

Is it possible to use the entity framework 4.0 in Visual Studio 2008? I hope MS does not expect us to keep buying a new IDE every 2 yrs ;)

# Web开发技术 said on May 30, 2009 10:16 PM:

Last week I mentioned in the sneak preview on POCO that support for POCO entities is one of the new capabilities

# Web开发技术 said on May 30, 2009 11:49 PM:

【译者按】 Entity Framework 1.0 发布也有一段时间了,但感觉用的人很少。其中一个很大的原因,也许就是不支持POCO。要知道,Entity Framework 1.0的做法是让你的实体从EF的基类继承而来

# Ngoc Luu said on May 31, 2009 11:14 PM:

Will this code supported in this version of EF?

var products = from p in db.Products

                           select new Product

                           {

                               Id = n.Id,

                               Name = n.Name

                           };

I played with VS2010 Beta1 and this exception still occured while it is valid in LINQ to SQL:

"The entity or complex type 'Demo.Product' cannot be constructed in a LINQ to Entities query."

# #.think.in said on June 1, 2009 9:12 AM:

#.think.in infoDose #31 (24th May - 1st June)

# VS2010学习 said on June 3, 2009 11:41 AM:

Introduction: From the moment I put my hands on Visual Studio.Net 2010 Beta 1 and I’m targeting EF4

# VS2010学习 said on June 4, 2009 6:37 AM:

Going through the changes in Entity Framework 4.0 I must say MSFT really does take in feedback. I have

# Marcelo said on June 5, 2009 3:29 AM:

Hi

Can you, please, write a complete sample of generic repository and unit of work together, using EF.4.0

# Entity Framework Design said on June 10, 2009 4:06 PM:

There are currently two ways to get Entity Framework apps up and running, we call these Database First

# Alexander Gornik said on June 12, 2009 6:27 PM:

Hi. I've just tried the feature. Why can't i have some mapped properties in a base class and map to it's child where other mapped properties are contained?

i keep getting " The required property 'Name' does not exist on the type 'EFTest.User2'. " while the property is just in the base class (if i override it it works ok). I understand why linq to sql can't support such a scenario, but can't see a reason why you don't.

Can't you tune up you BindingFlags in the convention mapper ? :)

# VS2010学习 said on June 14, 2009 9:23 PM:

&#160; There are currently two ways to get Entity Framework apps up and running, we call these Database

# ADO.NET team blog said on June 16, 2009 7:08 PM:

If you have been watching this blog, you know that I have been discussing the various aspects of POCO

# berniea said on June 18, 2009 3:05 AM:

Usually I don’t really like generated stuff, somehow it seems like I always reach a certain point where

# paul said on July 12, 2009 11:43 AM:

This looks like a great step forward (finally allowing POCOs for domain models w/ EF). I'm curious as to why properties cannot be virtual, though.  Unless I misread.

NHibernate does it exactly the opposite way, where by default your properties should all be virtual to make it so they can generate subclassed proxies more easily and inject lazy loading and such.

# radyo dinle said on July 19, 2009 10:38 AM:

I meant Col1 (in my above question) for the POCO property!

# Muhammad Mosa said on August 4, 2009 6:47 PM:

uni-directional relationships is supported, the only restriction is that I should delete the related end navigation property that is not needed! but how I can do so?

# Linus Li said on November 10, 2009 8:52 AM:

It is very good short paper and get the point precisely. Nobody complains "The unit tests are failed!". Pops up "InvalidOperationException was unhandled by user code". The solution is to add "Microsoft.CSharp" into the reference of NorthwindModel.

Leave a Comment

(required) 
(optional)
(required) 

  
Enter Code Here: Required

Search

This Blog

Syndication

Page view tracker