Showing posts with label entity framework. Show all posts
Showing posts with label entity framework. Show all posts

Friday, 23 March 2012

Bad times with Entity Framework and WCF


I recently wanted to make some data from a .NET MVC website I built some time ago available externally via a web service. After a little research I decided WCF was the way to go and set about creating a test service class that would return some data which was accessed using the Entity Framework (unfortunately my ORM of choice at the time). It was more difficult than I expected. 

Setup

My project uses .NET MVC 3, Entity Framework and Ninject amongst other things. The first job was to make sure I could inject the required service classes into my WCF service. Fortunately this was a piece of cake thanks to this excellent blog post. I'm not going to go into the WCF configuration because, to be honest, my knowledge of WCF is rubbish.

Problems sighted over the starboard bow

Setting aside my total lack of experience with WCF the first issue I encountered was that some of my queries worked perfectly while others failed with the mysterious error message "The underlying connection was closed: The connection was closed unexpectedly". After much Googling and many dead ends I eventually stumbled upon a Stack Overflow post which suggested checking the event viewer. Low and behold I find a considerably more specific error message:

System.ServiceModel.CommunicationException: There was an error while trying to serialize parameter http://www.yoursite.co.uk:MethodCall. The InnerException message was 'Type 'System.Data.Entity.DynamicProxies.SomeType_795A7B31EA6BCD0D7B9CFE73379DD55F309C0BEE00A295CAF276B939BB5BF4E6' with data contract name 'SomeType_795A7B31EA6BCD0D7B9CFE73379DD55F309C0BEE00A295CAF276B939BB5BF4E6:http://schemas.datacontract.org/2004/07/System.Data.Entity.DynamicProxies' is not expected. 

Further Googling of this error revealed the problem. Lazy loading. Entity Framework supports lazy loading by default, provided your navigation properties are virtual. Unfortunately WCF does not support Entity Frameworks lazy loading. What a pain in the ass. It turns out that to disable lazy loading the ProxyCreationEnabled property of DbContext must be set to false, which leads to further difficulties. With lazy loading disabled any required navigation properties must be eagerly loaded, which unfortunately isn't possible by default. The only way that I am aware of to do this using Entity Framework is by calling the Include method explicitly for any navigation properties you want to return.

A solution

I found a solution, albeit one that was very specific to my needs. Firstly I created two separate database context classes that extended DbContext. One to be used for the web service, which set ProxyCreationEnabled to false and one for the WCF web service with ProxyCreationEnabled set to true. Fortunately using Ninject this was pretty straight forward. Secondly was the eager loading problem. I decided it would be almost impossible to specify exactly which properties needed to be eagerly loaded for each query, so the only other option I could think of was to eagerly load all the navigation properties. There are problems with this solution. It will likely return more data than is required and I'm only aware of how to load one level of navigation properties, which could also cause problems. By this I mean if entity A has navigation properties B and C, when returning a list of As, I can eagerly load properties B and C. If B and C have their own navigation properties they will not be loaded. To achieve this kind of eager loading I created a method which used reflection to get all the public properties from an entity and return a list of those which were navigation properties (in my case navigation properties could be identified by a common base class). Each of the navigation properties in the list could then be passed into the Include method to tell Entity Framework to eagerly load each property. After making these changes all my queries worked perfectly. Huzzah! 
 
As pleased as I was to get this working, to be honest I'm still not one hundred percent convinced that this solution will hold up. Unfortunately I can't think of a better one. Oh well, time will tell I suppose.



Monday, 15 August 2011

Saving foreign keys in Entity Framework 4.1

Problem

I've recently experienced a few issues using the Entity Framework. I'm not ashamed to admit I swore in it's general direction on several occasions. This particular problem was updating foreign key fields (called navigation properties in the Entity Framework). I still haven't entirely decided whether Entity Framework is the problem or I'm the problem, but regardless it confused me so I thought I'd write about it.

Example

public ActionResult Edit(Car car, int manufacturerId){     
car.Manufacturer = carService.GetManufacturer(manufacturerId);     
carService.Save(car);
}

Here I'm passing in a complete Car entity except for the foreign key Manufacturer which has to be passed in as a foreign key value and looked up. I assumed that this would work fine, but it doesn't. All the scalar fields are saved, but the navigation property is not. A little research turned up a lot of blogs and stackoverflow questions asking about this problem. It turns out there are two ways of dealing with foreign keys in the Entity Framework. Unfortunately to my mind, they're both rubbish. Firstly there is foreign key association, for which you specify the foreign key column. E.g. ManufacturerId. This means you have to manually load all navigation properties. I don't know about you, but I like less work, not more. The second way of using foreign keys is independent associations. This makes more sense because you reference the foreign key object (e.g. Manufacturer) and these objects can be lazy loaded. Now that's more like it. Unfortunately this seems a little flawed as well. Other people can explain this much better than me, but using an independent association the Car is not aware of any changes to it's navigation properties unless it's attached first. This is why the above example would successfully update all the scalar properties of the Car object but not Manufacturer. 

Less than perfect solution

I found a few solutions to this problem. One was to manually tell the Entity Framework that the navigation property has changed. I really don't like that solution because it seems like unnecessary effort. That, and the fact that I've put hours into an application I've written using generic repositories and it would be a massive pain in the ass to change it all now. Another solution I found was to load the object first, then make the changes to the navigation property. Because the entity is attached, the Entity Framework tracks the changes to the navigation property. There's still a small problem, you have to copy all your changed properties submitted by the user to the object loaded from the database. What?!? I can't be bothered doing that for all my entities! They could have loads of properties. Fortunately I found a few posts mentioning a .NET MVC method called TryUpdateModel. It's pretty poorly documented but what it seems to do is use some kind of magic to copy all matching properties from your view model to the object passed into the method.

Below is my updated example code:

public ActionResult Edit(Car car, int manufacturerId) {     
Car carToSave =  carService.GetCar(car.Id);     
TryUpdateModel(car); // Copy all from car to carToSave          
car.Manufacturer = carService.GetManufacturer(manufacturerId);     
carService.Save(car);
}

As a side note if you view model contains the object you what to save (e.g. MyViewModel.Car) you can pass a "prefix" into the TryUpdateModel method which tells it where to look for matching properties. E.g.

public class MyViewModel {
  public Car Car { get; set; }     
  public int ManfacturerId { get; set; }
}
TryUpdateModel(car, "Car")