DCSIMG
Data Access With The Entity Framework - .NET Geek

.NET Geek

"It is upon the Trunk that a gentleman works" - Confucius

Data Access With The Entity Framework

A lot has been written about L2S and the Entity Framework over the last few weeks since the announcement that the Microsoft Data Team will focus their efforts on the Entity Framework. A lot has also been written about all the deficiencies the Entity Framework has and that it is not ready for prime time.
For us the Entity Framework has greatly simplified data access across the board.

Data Access code is tedious, repetitive and boring. I don’t want to focus my energy on how to access data. It should be simple, fast and it should just work. While stored procedures still have their place in certain scenarios and certain environments, most of the time writing sql by hand is a waste of your customers money. Most ORMs will do the work at least as well as you do, if not better. In edge cases you will have to tweak, but for mainstream scenarios the sql generated by most ORM tools is good enough.

I want to point out that this is not an introductory post on how to use the Entity Framework. If you want information on how to work with it, we have assembled a good list on our site. So without further delay, let’s see how we use the Entity Framework at Renaissance.

We made an early decision that we don’t want the Entity Framework to leak too much into our services. For that reason we access our model using the fairly standard repository pattern.

Here’s the main repository interface.

public interface IRepository : IDisposable

{

    T[] GetAll<T>();

    T[] GetAll<T>(Expression<Func<T, bool>> filter);

    T GetSingle<T>(Expression<Func<T, bool>> filter);

    T GetSingle<T>(Expression<Func<T, bool>> filter, List<Expression<Func<T, object>>> subSelectors);

 

    void Delete<T>(T entity);

    void Add<T>(T entity);

    int SaveChanges();

 

    DbTransaction BeginTransaction();

}

As you can see from the interface, the Getters return a generic type or an array of a generic type. Delete and Add affect the repository instance, but will not hit the database. To commit any pending changes in the repository we call the SaveChanges method. If you’re not familiar with C# 3.0 expressions, the code “Expression<Func<T, bool>> filter” might look a little cryptic. Don’t worry, from the consuming side you don’t have to deal with this. What these expressions facilitates, is to allow us to use Lambda Expressions as a specifications for our repository.
The parameter “List<Expression<Func<T, object>>> subSelectors” requires some additional explanation. The Entity Framework will not retrieve related entities when you request a top level entity. For example, if you have a customer that can have many orders you will not receive the orders when you query for a customer. The Entity Framework will only retrieve related data if you explicitly tell it to do so. I don’t have a huge issue with this, but I know a lot of others do. What did bother me tremendously though, was the fact that you have to specify the related entities using string literals.
For example: context.Customer.Include("SalesOrderHeader.SalesOrderDetail");
This was pretty much a showstopper for me, so we introduced the IncludeBuilder. The IncludeBuilder allows you to retrieve related entities as well, but strongly typed. More on that later.


Ok, enough background, let’s look at the code that consumes the repository.
Here’s a simple example of adding a new data.

using (var repository = _factory.Create())

using (var tx = repository.BeginTransaction())

{

    Customer customer = new Customer();

    customer.FirstName = firstName;

    repository.Add<Customer>(customer);

    repository.SaveChanges();

 

… Some more code that requires transaction management…

 

    tx.Commit();

}

The boilerplate code is generated by a custom CodeRush template “nrp” aka “New Repository” (I just had to insert something related to CodeRush :-) )

 

Here’s a standard example of retrieving a customer with an ID of 10.

Customer customer = repository.GetSingle<Customer>(p => p.CustomerId == 10);

It can’t get much simpler than that.

If we want to retrieve an entity with its related entities the code is a little more involved, but remember, boiler plate is generated. (Snippets is a decent option if you don’t have CodeRush or R#)

 

var builder = new IncludeBuilder<Customer>();

builder.Add(p => p.Orders);

customer = repository.GetSingle<Customer>(p => p.CustomerId == customerId, builder.Includes);


If you often retrieve the same hierarchy of data you could always create a specialized repository that implements the IRepository interface and add a GetCustomerWithOrders() method. If you have many variations this will become a burden though.

 

To summarize, I am basically a happy camper with the Entity Framework. It has a some rough edges, but nothing we haven’t been able to work around.

kick it on DotNetKicks.com

Comments

DotNetKicks.com said:

You've been kicked (a good thing) - Trackback from DotNetKicks.com

# November 12, 2008 4:09 PM

Daniel said:

Have you tested this using other IRepository implementations?  I've been trying to accomplish the same thing, but in my experience too much of the implementation "leaks" through.  For example, try creating an XmlRepository or SqlDataServicesRepository - the filters end up not being compatible between repositories.

# November 12, 2008 8:58 PM

Kim said:

@Daniel, the only other implementation is an InMemoryRepository. This implementation works off a List<> and on queries basically just compiles the filter predicate expressions and check against that. No leakage so far. :-)

# November 13, 2008 4:14 AM

Jackie Goldstein's Weblog (In Israel) said:

Kim has a new post that summarizes some of our experience using the Entity Framework in a real client

# November 13, 2008 7:03 AM

Jackie Goldstein's Weblog said:

Kim has a new post that summarizes some of our experience using the Entity Framework in a real client

# November 13, 2008 7:03 AM

aCoder said:

Why all the overloads in the interface?

Why not just have a method "IQueryable<T> QueryFor<T>()"

and then you can filter, fetch all, fetch single, join, use any linq query operator.

The only problem I see is that the client of IRepository, should have problem

with some LINQ queries when the EF is used underneath. For example, a query like:

repository.QueryFor<Customer>().Single(c => c.Id == 1) would fail since the EF only

supports First() and will throw on Single(). (assuming I remember well)

If you need more syntactic sugar or shortcuts, you can then have extension methods on your IRepository.

As long as it returns an IQueryable you can do anything you want. For example:

public static T FindOne<T>(this IRepository repository, int id) where T : IIdentifiable {

   return repository.QueryFor<T>().FirstOrDefault(x => x.Id == id);

}

Also, can you explain the scenario for the BeginTransaction() method on IRepository?

Shouldn't this be handled internally when you call SaveChanges()?

# November 13, 2008 10:43 AM

Scott Allen said:

Kim:

I'm curious to see the implementation for just one of your Get methods for IRepository. Specifically, how you map the generic type parameter to an entity set? I've done it using string mappings, but I'm not too happy with it. Can you share?

# November 13, 2008 12:59 PM

Kim said:

@aCoder,

What do you mean by *all* the overloads ? this was the expressiveness I wanted.

"Why not IQueryable<T>..." - The short answer is that I wanted to prevent deferred execution. The longer answer is more related to design and preferences and that will have to wait for maybe another post.

Transactions - I'm not sure what's not clear about the need for explicit transactions. In a service we often need to write something to the database. Under certain conditions we need to roll that back.

# November 13, 2008 1:52 PM

Kim said:

@Scott - The Scott Allen from Herding Code? I'm a fan!

Regarding the

"map the generic type parameter to an entity set?"

I have to check.

...Just sent you an email through your blog.

# November 13, 2008 2:19 PM

Craig said:

One of big problems I have heard about EF is the designer is really slow if your DB has > 150 tables. Have you experienced this?

# November 13, 2008 3:29 PM

Kim said:

If a database has 150 tables, it is possible that they don't all make sense in the same context so you could maybe create a few models. Having said that, the designer is not good enough for big databases. You should at least be able to partition your .edmx into sub views. Maybe in v2...

We have no .edmx with more than 50 entities. Another point to take into consideration, is that the larger the .edmx the longer the instantiation time the first time you access the object context. I know you can precompile it or something like that, but we haven't had a need for that yet. On my laptop it takes about 1.5 seconds to do the first instantiation and then it drops to a couple of ms.

If you have used any advanced modeling tool like ERWin you won't feel comfortable in the EF designer.

Oh, you asked about the speed, sorry. With 50 tables it is fine on a high end dev pc. Haven't tried with more.

# November 13, 2008 4:33 PM

.NET Geek said:

In my last post I explored a little about how we use the Entity Framework. One question that comes up

# November 14, 2008 2:49 AM

.NET Geek said:

I just read a post “Entity Framework - Disappointment” where a decision was made to ditch the EF because

# November 17, 2008 5:32 PM

Coffee, smoke and techilicious burps at 3.47 AM said:

Entity Framework, Eager Loading and Lazy Loading, my own 2 cents. For those new to Entity Framework,

# January 28, 2009 5:31 PM

infoblog » Are you Eager? Or are you Lazy? Or are you both on a case to case basis…??? said:

Pingback from  infoblog &raquo; Are you Eager? Or are you Lazy? Or are you both on a case to case basis&#8230;???

# January 28, 2009 5:42 PM

Coffee, smoke and techilicious burps at 3.47 AM said:

Entity Framework, Eager Loading and Lazy Loading, my own 2 cents. For those new to Entity Framework,

# January 28, 2009 5:56 PM

Windows 7 News » Are you Eager? Or are you Lazy? Or are you both on a case to case basis…??? said:

Pingback from  Windows 7 News &raquo; Are you Eager? Or are you Lazy? Or are you both on a case to case basis&#8230;???

# January 29, 2009 4:09 AM

Abstracting the Data Access Layer - Quickduck said:

Pingback from  Abstracting the Data Access Layer - Quickduck

# May 18, 2009 8:31 AM

John said:

How do you add Customer object to context

repository.Add<Customer>(customer);

repository.SaveChanges();

Can you write down the Add Method of repository class

# September 3, 2009 5:18 PM

Are you Eager? Or are you Lazy? Or are you both on a case to case basis…?? | Ideas and Coffee at 3.47 AM said:

Pingback from  Are you Eager? Or are you Lazy? Or are you both on a case to case basis&#8230;?? | Ideas and Coffee at 3.47 AM

# March 26, 2010 5:41 AM

Silhouette Rimless Titanium Nose Pads, Titan Bulb Wac - 393.ja3ra.com said:

Pingback from  Silhouette Rimless Titanium Nose Pads, Titan Bulb Wac - 393.ja3ra.com

# May 24, 2010 2:33 PM

1993 Honda Prelude 2.3, Replacement Engine Honda Prelude Parts - 491.cmanager.org said:

Pingback from  1993 Honda Prelude 2.3, Replacement Engine Honda Prelude Parts - 491.cmanager.org

# May 24, 2010 5:52 PM

Clk500 Parts Computer Front Bumper, Clk500 Sample Locate - 268.codebluehacks.org said:

Pingback from  Clk500 Parts Computer Front Bumper, Clk500 Sample Locate - 268.codebluehacks.org

# May 24, 2010 8:24 PM

Spectra5 Auto Kia Sportage, Kia Spectra5 Second Hand Automotive - 350.unlockiphone30.net said:

Pingback from  Spectra5 Auto Kia Sportage, Kia Spectra5 Second Hand Automotive - 350.unlockiphone30.net

# May 24, 2010 11:23 PM

Stan Getz Bossa Nova Torrent, Toyota Navigation Torrent - 457.zapstreaming.com said:

Pingback from  Stan Getz Bossa Nova Torrent, Toyota Navigation Torrent - 457.zapstreaming.com

# May 25, 2010 12:35 PM

2010 Milan Pictures, Mercury Milan Reliability - 266.animejin.com said:

Pingback from  2010 Milan Pictures, Mercury Milan Reliability - 266.animejin.com

# May 26, 2010 1:55 AM

Cj5a Sale Wagoneer 1981 Jeep Cj7, Cj5a Girl Forums - 415.unlockiphone30.net said:

Pingback from  Cj5a Sale Wagoneer 1981 Jeep Cj7, Cj5a Girl Forums - 415.unlockiphone30.net

# May 26, 2010 3:16 AM

2004 - 1985 @ 320i 2000, 1981 Bmw 320i Dimensions - 482.binggreen.com said:

Pingback from  2004 - 1985 @ 320i 2000, 1981 Bmw 320i Dimensions - 482.binggreen.com

# May 31, 2010 9:09 AM

ToratordDrale said:

Lyricz74|&lt;3 Just thinking about his death brings tears to my eyes. If anyone deserved aп»ї happy ending, he did. R.I.P.

 http://24pharmshop.com/?p=413

thplousaqq

# February 25, 2011 11:18 PM
Leave a Comment

(required) 

(required) 

(optional)

(required) 


Enter the numbers above: