Entity Framework context operations in perspective with their entry states

When manipulating data with Entity Framework and the context, you are changing the state of the entity. For example, if you insert a new entity, the state will be to “Added”. This article will show you all context operation that change the entity state and will show you that you can do what most of the operation do by simply changing manually the state of the entity.

Before going deeper with the operation, let see all states. You can get the list of states by going into EntityState class of System.Data.

namespace System.Data
{
  [BindableType(IsBindable = false)]
  [Flags]
  public enum EntityState
  {
    Detached = 1,
    Unchanged = 2,
    Added = 4,
    Deleted = 8,
    Modified = 16,
  }
}

The Detached state is when an object is not yet attached to Entity Framework’s context. By default, if you create a new instance of a class, this one is not attached. Another way to be detached is when you delete an entity. This one will be deleted from the database by Entity Framework but the object reference remains in your code. This one will be back to detached. Having said that, moving back to detached won’t delete the entity but won’t make Entity Framework knows about it. We could also manually set the entry to detached to have this one not tracked.

var category = context.Categories.Find(id);
context.Categories.Remove(category);
context.SaveChanges(); // Will delete and set category as detached
//Is the same as
var category = context.Categories.Find(id);
context.Entry(category).State = EntityState.Detached;
context.SaveChanges(); // Will do nothing in the database because it's detached and it would required to be "Deleted" to be deleted.

The example above call Remove to delete the entity. When deleting the state goes from Added to Delete to Detached. So both code below are doing the same thing : delete the entity from the database.

var category = context.Categories.Find(id);
context.Categories.Remove(category);
context.SaveChanges();
//Is the same as
var category = context.Categories.Find(id);
context.Entry(category).State = EntityState.Deleted;
context.SaveChanges();

The Unchanged state occur when the entity is tracked by Entity Framework’s context but has not changed yet. You can have this state if you use the method Attach() or if you change the state with Entry().

var category = new Category{Id=123};
context.Categories.Attach(category);
context.SaveChanges();
//Is the same as
var category = new Category{Id=123};
context.Entry(category).State = EntityState.Unchanged;
context.SaveChanges();

The Added state is synonym of insertion. When a new entity is added to the context, this one will be inserted into the database. In Entity Framework words, it’s called Added. This can be done by using the Add method or by changing the state to EntityState.Added.

var category = new Category{Id=123};
context.Categories.Add(category);
context.SaveChanges();
//Is the same as
var category = new Category{Id=123};
context.Entry(category).State = EntityState.Added;
context.SaveChanges();

Finally, you can be Modified. This state will do an update to the property that has been changed. Once the update has been done by calling SaveChanges, the state come back to attached

var category = context.Categories.Find(id); //State is to attached
context.Categories.Update(category); //State is now updated
context.SaveChanges(); //State is now attached
//Is the same as
var category = context.Categories.Find(id); //State is to attached
context.Entry(category).State = EntityState.Modified; //State is now updated
context.SaveChanges(); //State is now attached

Without going in to much details you can handle modified state by using “ApplyCurrentValues“. This will check the object passed by parameter and if changes are found will mark those properties with the new value and with the Modified state.

var category = context.Categories.Attach(new Category { ID = categoryThatCameFromUserForm.ID });
context.Categories.ApplyCurrentValues(categoryThatCameFromUserForm);
context.SaveChanges(); //State is now attached

We could also specify manually which property that could have been changed with Entry method.

var category = context.Categories.Attach(new Category { ID = categoryThatCameFromUserForm.ID });
context.Entry(category).Property(d=>d.Name).IsModified = true;
context.SaveChanges(); //State is now attached

To conclude, it’s possible to handle Entity Framework’s entities with several approaches. The method one, with operation, is perfect for simple case when the method two, with state, is better to have further control over what is modified and to create abstract level over Entity Framework if requires. For example, you could easily add some code that check if the Id is Null or not, if it’s null to change the state to Added, otherwise to set the state to Modified.

JQPlot with Internet Explorer 7 and 8 : do not forget excanvas.js

JQPlot is a javascript library that make easy to have graphic on your website. By default, it uses all the power of Html5.

dragdrop2

If you want to use JQPlot with Internet Explorer 8, add this line before adding the JQPlot’s javascript files.

	<!--[if IE]><script language="javascript" type="text/javascript" 
	src="@Url.Content("~/Scripts/libs/plot/excanvas.js")"></script><![endif]--> 

Ths Javascript library can be found on Google Project.

This will let the library use the excanvas.js instead of the Html5 one.

Automapper Ignore vs UseDestinationValue, what is the difference?

Automapper gives you big leverage when it’s the time to transfer values from one object into another object. While most of the transfer is done automatically with AutoMapper, sometimes, specific values must not be transferred. Imagine the case for a destination class that has not the property or for a class that has do not want the value from the source but will compute the value in its constructor.

Automapper gives the property Ignore which tells the mapper to not take the value of a property from the source class. Ignore not only ignore the mapping for the property, but also ignore the mapping of all inner properties. It means that if the property is not a primitive type, but another class, that if you are using Ignore, this class properties won’t be mapped. So, A.B.C would be A.Null.

But, if you have a scenario that you must not map a property, but map all inner properties should remain then you should use UseDestinationValue. That will end to be A.B.C -> A.B.C (where B is from the destination class, not the source class, probably initialized in the destination’s constructor).

To conclude, Ignore method will not map any property, neither the inner properties of the property defined to be ignored. UseDestinationValue will not map the property. It keeps the existing value of the property but will map the value of this one. It’s the same with a collection. The reference of the collection stays the same while the object inside is mapped.

Validation failed for one or more entities. See ‘EntityValidationErrors’ property for more details.

The problem with the error “Validation failed for one or more entities. See ‘EntityValidationErrors’ property for more details.” is that you cannot go inside it. In fact, you need to cast this one into DbEntityValidationException to be able to see inner errors.

dbentityvalidationexception

To see the exception details, you need to open the watch window, or the immediate window and type this line :

    ((System.Data.Entity.Validation.DbEntityValidationException)$exception).EntityValidationErrors

From here, you will be able to see which entities are problematic and also what inner validation errors has been thrown.

How to include correctly property within a collection when using Entity Framework code first

I have several example in this website that include with a string the property when it’s a property inside a collection of my main entity. Here is one example:

return DatabaseContext
              .SetOwnable<Workout>()
              .Include(x => x.Sessions)
              .Include("Sessions.WorkoutSessionExercises")
              .Include("Sessions.WorkoutSessionExercises.Exercise")
              .Single(c => c.Id == id);

At least, this example use the property for the Sessions. But why I wrote with a string for the two others includes? Because Sessions is a collection which doesn’t let me link to one of its property. Instead, it links me to a list of property of the collection. This is quite logic if we think about it. However, I remain with the problem of using string which will lead in the maintenance phase to some possible problem when refactoring. Renaming a property won’t change the string. This is why it would be better to specify the property of the collection.

This can be done by using the Linq method “Select“.

return DatabaseContext
              .SetOwnable<Workout>()
              .Include(x => x.Sessions)
              .Include(x => x.Sessions.Select(d=>d.WorkoutSessionExercises))
              .Include(x => x.Sessions.Select(d=>d.WorkoutSessionExercises.Select(g=>g.Exercise)))
              .Single(c => c.Id == id);

As you can see, we load the collection Sessions, then we load the collection WorkoutSessionExercise which is inside every Session. Finally, we load every Exercise that is a property without being a collection.

This example show you that even with multiple collection deep you can still avoid using string to specify that to include and what not.

How to create an Html Extension like ActionLink to create link only if the user has the authorization

The idea to create an Html Extension like ActionLink to create link only if the user has the authorization can be very helpful. The goal here is to display the link only if the action allow the user to execute the action. This way, every user will see link to action that it belong to. On the other hand, people with the access to these actions will see links to those action.

Here is an example of the final product. The first line is the new ActionLink and the second line is the default one. The result will be that a user that has access to “Edit” will see the link when others that doesn’t have access won’t see it. The second line will show for every body the link for “Details”.

  @Html.Input().ActionLink("Edit", "Edit", null, (new { id=item.Id }))
  @Html.ActionLink("Details", "Details", new { id=item.Id })

On the controller side, you will see the Edit action with the authorization attribute.

[HttpGet]
[Authorize(Roles = Roles.ADMINISTRATOR)]
public ActionResult Edit(int id)
{
    //...
}

First of all, we need to create a class to be able to get the attribute of the action. Here is the class.

public class AttributeHelper
    {
        private readonly HtmlHelper _htmlHelper;
        public AttributeHelper(HtmlHelper htmlHelper)
        {
            _htmlHelper = htmlHelper;
        }

        public IEnumerable<Attribute> GetAttributes(
                        string actionName,
                        string controllerName,
                        string method = "GET")
        {
            var controllerFactory = ControllerBuilder.Current.GetControllerFactory();
            var otherController = (ControllerBase)controllerFactory.CreateController(new RequestContext(_htmlHelper.ViewContext.HttpContext, new RouteData()), controllerName);
            var controllerDescriptor = new ReflectedControllerDescriptor(otherController.GetType());
            var controllerContext2 = new ControllerContext(new HttpContextWrapperWithHttpMethod(_htmlHelper.ViewContext.HttpContext.ApplicationInstance.Context, method),
                     new RouteData(), otherController);
            var actionDescriptor = controllerDescriptor.FindAction(controllerContext2, actionName);
            var attributes = actionDescriptor.GetCustomAttributes(true).Cast<Attribute>().ToArray();
            return attributes;
        }

        private class HttpContextWrapperWithHttpMethod : HttpContextWrapper
        {
            private readonly HttpRequestBase _request;

            public HttpContextWrapperWithHttpMethod(HttpContext httpContext, string method): base(httpContext)
            {
                this._request = new HttpRequestWrapperWithHttpMethod(httpContext.Request, method);
            }

            public override HttpRequestBase Request
            {
                get { return _request; }
            }

            private class HttpRequestWrapperWithHttpMethod : HttpRequestWrapper
            {
                private readonly string _httpMethod;

                public HttpRequestWrapperWithHttpMethod(HttpRequest httpRequest, string httpMethod): base(httpRequest)
                {
                    this._httpMethod = httpMethod;
                }

                public override string HttpMethod
                {
                    get { return _httpMethod; }
                }
            }
        }

    }

If you want to use it, you must call the method and then search for the required attribute.

var attributeHelper = new AttributeHelper(HtmlHelper);
var att = attributeHelper.GetAttributes(actionName, controllerName).OfType<AuthorizeAttribute>();
var isInRole = att.Aggregate(false, (f, g) => f | HtmlHelper.ViewContext.HttpContext.User.IsInRole(g.Roles));

Line 1 instantiate the helper that will give you the possibility to get attributes. The second line will filter to get AuthorizedAttribute. This can return multiple attribute so we have to use the third line to aggregate if the user is in one of the AuthorizedAttribute.

The Html helper can now use this to display or not the link.

public MvcHtmlString ActionLink(string linkText
                                        , string actionName = null
                                        , string controllerName = null
                                        , object routeValues = null
                                        , object htmlAttributes=null)
{
	if (actionName == null)
	{
		actionName = HtmlHelper.ViewContext.RouteData.GetRequiredString("action");
	}
	if (controllerName == null)
	{
		controllerName = HtmlHelper.ViewContext.RouteData.GetRequiredString("controller");
	}
	var routeValues2 = new RouteValueDictionary(routeValues);
	var attributes = (IDictionary<string, object>)HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);

	if (string.IsNullOrEmpty(linkText))
		throw new ArgumentException("linkText");
	else
	{
		var attributeHelper = new AttributeHelper(HtmlHelper);
		var att = attributeHelper.GetAttributes(actionName, controllerName).OfType<AuthorizeAttribute>();
		var isInRole = att.Aggregate(false, (f, g) => f | HtmlHelper.ViewContext.HttpContext.User.IsInRole(g.Roles));
		if (isInRole)
		{
			return MvcHtmlString.Create(HtmlHelper.GenerateLink(HtmlHelper.ViewContext.RequestContext, HtmlHelper.RouteCollection, linkText, (string)null, actionName, controllerName, routeValues2, attributes));
		}
		return new MvcHtmlString("");
	}
}

Line 9 and 13 are only there if the controller or and action is not defined. In practice, the controller shouldn’t be used all the time because we are most of the time using an action that is inside the controller. For example, we are in the Index of the controller Muscle. If we want to Edit, Create, etc, all of theses action are in the controller, it doesn’t require you to specify every time the controller.

How to secure your Web Api Controller globally without having to use Authorize attribute

If you are using Web Api of .Net 4.5 framework and want to have the same behavior of Asp.Net MVC which let you have global authorization set to every http request, than you need to configure your website differently.

In Asp.Net you would add a new filter to the FilterConfig file.

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
    filters.Add(new HandleErrorAttribute());
    filters.Add(new AuthorizeAttribute());
}

But, this won’t work with the Api controller. You have to set the AuthorizeAttribute to the WebApiConfig file.

public static void Register(HttpConfiguration config)
{
	config.Routes.MapHttpRoute(
		name: "DefaultApi",
		routeTemplate: "api/{controller}/{id}",
		defaults: new { id = RouteParameter.Optional }
	);

	config.Filters.Add(new AuthorizeAttribute());
}

From here, every method of all your controllers will require authorization. If you want to remove this required authorization for specific web method, you need to add the attribute [AllowAnonymous]. You can have additional information directly at Microsoft.