Idiot’s guide to Entity Framework by an Idiot

I recently used Entity Framework for a project for the first time and my Boss wanted to take a look at Entity Framework so I wrote up a 101 guide for him and he thought it was good. This blog is probably full of inaccuracies as I’m a noob at EF but I think it has a few helpful tips.

So the way I like best is to create your database first then have EF generate your objects for you. You get complete control over your DB tables so you can make them as efficient as possible and when using code first EF has been spotty with making database structure changes.

When creating your database make sure to set up the FK / PK metadata relationships so EF can load it up. For PKs make sure to set Identity specification to YES or EF will assume you are providing your own PKs when creating a new object. If you generate your edmx file before setting identity specification to YES it will bug out if you try to change it yes then update the file, so you then have to manually change it in the properties of the identity column in the ef designer.

Also ALWAYS include a PK for a table, this is generally a really bad idea not to use a PK and with EF it is an even worse idea that will only end in tears(lots of bizarre exceptions).

You can also use EF by creating a model in their edmx file gui editor and generating a DB from that or by coding your objects and having it generate a DB from that.

Steps to add EF to your project:

1. EF should already come with vs2012/vs2013 but use nuget to install if you don’t have it (http://msdn.microsoft.com/en-us/data/ee712906.aspx)

2. Add a new file to the project, choose “ADO.NET Entity Data Model” under Data.

3. Choose generate from database, connect to it and run through the wizard

You now have a .edmx file which is all the auto generated crap EF just made for you. Clicking the .edmx file will bring up the gui editor where it should have loaded all of your tables up. All of the .tt file stuff underneath the edmx file is auto generated files that you should not edit unless debugging.

So EF just generated a bunch of awesome POCOs for you. These POCOS have their pk/fk relationships set up as virtual objects which will only load when referenced when lazy load is enabled(it is by default).

It also generated a DbContext class for your db that will be named whatever you named it in the wizard. The DBContext class is what you use whenever you want to get to your data, it manages all of the database query/persistence/connection and what not. DbContext classes are a combination of unit of work/repository patterns.

Simple use to get 1 object

StoreContext context = new StoreContext(); Account a =
 context.Accounts.FirstOrDefault(a => a.AccountId == 1); 
System.Print(a.Purchases.count); 
//woo all our purchases loaded up automatically 
context.dispose();

 

So whenever we get an object  from a context it is going to be associated with that context. When we call context.dispose() and then try to call a.Logins it will throw an exception because it never loaded our logins and our context is gone now.

A context should be used like a unit of work because it is not thread safe and leads to memory/sharing issues. So when we want to do a task we create a new context make our changes and call context.SaveChanges() then get rid of the context. For an asp.net site I would use one context per request so every time a request is made in the global.cs I would create a new context and store it as StoreContext.Current() then when the request is done  dispose of the context.

So add a a current method like this to your context class. This checks if a context has been created for a request yet and if it has it it returns it if not it creates a new context and returns it.

public static MySweetContext Current()
 {
     if (!HttpContext.Current.Items.Contains("context"))
     {
         HttpContext.Current.Items.Add
         ("context", new MySweetContext());
      }
      return HttpContext.Current.Items["context"] 
      as MySweetContext 
 }

And to dispose of it after each request add something like this

MySweetContext currentContext = 
HttpContext.Current.Items["context"] as MySweetContext;
if (currentContext != null)
    currentContext.Dispose();

in your Application_EndRequest(object sender, EventArgs e) method in your global.asax file.

 

For a web api service you should create a new context in your object controller every request, you can actually generate basic controllers from entity framework entities that will have this in there already. Microsoft spent some time making the DbContext class fast to instantiate so I wouldn’t worry about creating one to often.

Moving an object between contexts is a complete PITA of attaching/detaching and setting things to null. I fell into a trap of trying to do this because of storing an object in a session variable with a context associated with it and then making a new request that had a new context. Don’t be like me use your objects then get new ones with a new context. Screw trying to be efficient with this.

For a web service you are pretty guided away from falling into this, but be warned moving between contexts is awful and generally means you shouldn’t be doing what you are doing if you have to.

Rest/JSON ef web api stuff,

1. to generate a basic controller from an EF object right click a folder and add scaffold and follow the wizard from there.

2. Web API with JSON is dumb with object relationships by default, it will get stuck in a loop. To fix this you can add

GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling 
= Newtonsoft.Json.ReferenceLoopHandling.Ignore;

WebApiConfig.Register(GlobalConfiguration.Configuration);

to your global.asax.cs start method. This will stop the loops and load up every single virtual object down to its termination.

OR you can disable lazy loading in your context. This might be better because with a web service you are trying to limit what your sending down so specifying exactly what you load is going to be needed.

One idea for this is to extend your Context class to a class named something like JSONContext, then disable lazy loading in its constructor and use it in the service controllers. So when you need to load a virtual object you have to do explicitly by using the Include method

context.Accounts.Include(A=> A.logins).FirstOrDefault(A => A.id == id)

Random cool things

1. EF protects against SQL injection and whatnot by itself as long as you use the objects with LINQ like your supposed to, if you manually enter in some SQL code to the connection you are on your own.

2. You can bind values to enums in the .edmx designer or bind an already made enum class to an enum column ( I believe the later requires .net 4.5 though)

3. Some say you should wrap EF with a repository and unit of work pattern so it is abstracted away and allows your unit tests to be pure. However EF already is pretty much a repository/unit of work pattern, I don’t think this is necessary honestly. For a small project don’t bother but for something larger it’s pretty debated and you should google it.

4. EF can handle polymorphism with your POCOs in the ef designer by using a tinyint or byte column to differentiate the classes.

5. I extend my POCOs by creating a partial class in a new file, your base poco files are auto generated so don’t edit them. EF in a normal project(vs an asp site) will create separate class files in the model folder which means if you want to keep the same file names for this partial extension you have to put them in a separate folder and go against namespace standards of using the folders. You can’t have a partial class in a different namespace unfortunately

6. To update your EF file from DB Right click and then hit update in the EF designer and then hit save and it will regenerate.

Thanks for reading my blog! Hopefully it didn’t kill too many brain cells.

This entry was posted in Uncategorized. Bookmark the permalink.

One Response to Idiot’s guide to Entity Framework by an Idiot

  1. Pingback: Windward Releases "Idiot’s Guide to Entity Framework (by an Idiot)" | SaaS Newswire

Leave a Reply