As I’ve said, the POCO entity classes that you create when you use the DbContext API don’t use proxy tracking unless they comply with some strict rules. Here they are:
In order for the DbContext
to generate change-tracking proxies from your classes, the following must be true:
• The class must be public.
• The class must not be sealed (NotInheritable
in Visual Basic).
• The class must not be abstract (MustInherit
in Visual Basic).
• The class must have a default (parameterless) constructor.
• The default constructor must be public or protected.
• Each property of the class must have public and virtual (Overridable
in Visual Basic) get
and set
accessors.
• Collection navigation properties (the many-side) must be declared as ICollection<T>
.
In addition, you should use the DbSet.Create()
method instead of the constructor when you create an entity if you want the proxy type to be created when you create the object. Be aware that Create()
does not add the entity to the DbSet
. You still need to call the Add()
method to do that.
Make A Note
The classes created by the Designer don’t comply with these rules. If you want to use the Designer and you want change-tracking proxies, you’ll have to edit the T4 template using the techniques you learned in Chapter 6.
Put On Your Thinking Hat
Here’s a simple class definition for a Recipe
class. Can you change it so that Entity Framework will use a change-tracking proxy if it is instantiated using DbSet.Create()
?
public class Recipe
{
public Int32 RecipeID {get; set;}
public String RecipeName {get; set;}
public String Headnote {get; set;}
public IList<RecipeIngredient> Ingredients {get; set;}
public IList<RecipeStep> Steps {get; set;}
}
Public Class Recipe
Public Property RecipeID As Int32
Public Property RecipeName As String
Public Property Headnote As String
Public Property Ingredients As IList(Of RecipeIngredient)
Public Property Steps As IList(Of RecipeStep)
End Class
Put On Your Thinking Hat
How’d you do? This code was pretty clean; all we had to do was make the properties virtual and change the IList<T>
collection properties to ICollection<T>
.
Here’s the original, which would use snapshot change-tracking:
Public Class Recipe
Public Property RecipeID As Int32
Public Property RecipeName As String
Public Property Headnote As String
Public Property Ingredients As IList(Of RecipeIngredient)
Public Property Steps As IList(Of RecipeStep)
End Class
To trigger the creation of change-tracking proxies, we have to change the definition to this:
public class Recipe
{
public virtual Int32 RecipeID {get; set;}
public virtual String RecipeName {get; set;}
public virtual String Headnote {get; set;}
public virtual ICollection<RecipeIngredient> Ingredients {get; set;}
public virtual ICollection<RecipeStep> Steps {get; set;}
}
Here’s the original, which would use snapshot change-tracking:
Public Class Recipe
Public Property RecipeID As Int32
Public Property RecipeName As String
Public Property Headnote As String
Public Property Ingredients As IList(Of RecipeIngredient)
Public Property Steps As IList(Of RecipeStep)
End Class
To trigger the creation of change-tracking proxies, we have to change the definition to this:
Public Class Recipe
Public Overridable Property RecipeID As Int32
Public Overridable Property RecipeName As String
Public Overridable Property Headnote As String
Public Overridable Property Ingredients As ICollection(Of RecipeIngredient)
Public Overridable Property Steps As ICollection(Of RecipeStep)
End Class
Take A Break
Change-tracking got pretty complicated pretty fast, didn’t it? Relax. It’s sometimes convenient to manipulate the state of an entity, and we’ll look at some validation methods that are exposed by the DbEntityEntry
in the next section, but other than that it’s not something you need to worry about very often. Why don’t you take a break now, before you complete the Review and we look at the last subject of the chapter: data validation?