Compartir a través de


Feature CTP Walkthrough: Self Tracking Entities for the Entity Framework (Updated)

The goal of this walkthrough is to demonstrate a basic scenario for the use of the Self-Tracking Entities feature of Entity Framework.

Self-Tracking Entities consist on a set of code generation templates based on Text Template Transformation Toolkit (T4) technology that is used to generate entity types that have the ability to record changes on scalar and complex property values, and on reference and collection navigation properties, independently of the Entity Framework.

The main scenario we are trying to address with Self-Tracking Entities is one in which a WCF service exposes a series of operations that return entity graphs, then a client application can manipulate that graph and submit the modifications to another service operation that validates changes in the graph and then applies them to the database store using Entity Framework.

While the following walkthrough uses C#, versions of the Self-Tracking Entities template exist for both C# and Visual Basic, and all the concepts described apply as well to the Visual Basic version.

Requirements

  1. This walkthrough requires Visual Studio 2010 Beta 2.
  2. The Microsoft Entity Framework Feature CTP 2 that is described here.
  3. A local SQL Server 2008 Express instance has to be installed as SQLEXPRESS. Otherwise, changes to the connection string in the web.config file or regenerating the database from the included SQL scripts may be necessary.
  4. Download and extract the initial solution attached to this post.

Walkthrough

For the sake of brevity we are going to start with a prebuilt Visual Studio solution. The solution is a simple WCF service for Blogging, and contains three projects:

  1. BloggingModel: this is a class library project containing an entity model created using the EDM designer.
  2. BloggingService: this is a WCF service, contains the definition of the service contract and some code for the service.
  3. BloggingConsole: this is a simple console application structured as a series of simple tests for the service.

To start, open the EDM model named Blogging.edmx that is included in the BlogginModel project.

Untitled

Adding the templates

The first step will be adding a T4 template for generating the self-tracking entities. In order to do that, from any blank area in the surface of the EDM designer, right click and select the “Add Code Generation Item…”

 

Untitled

This will display a standard “Add New Item” dialog. Select the item type “ADO.NET Self-Tracking Entity Generator”, specify “Blogging.tt” as the name, and click on Add.

Untitled

Note: As soon as the template files are added to the project, a security warning may pop up asking you to accept only if you trust the source of the template. Accept in order to continue with this walkthrough.

Notice that the BlogginModel project now contains two TT files: Blogging.Types.tt and Blogging.Context.tt.

What has just happened? When you add T4 templates for code generation like this, the default code generation used for Entity Framework models is turned off and the T4 templates take over that responsibility. T4 is a powerful code-generation tool included in Visual Studio. T4 templates can be modified by users to produce different code patterns based on the same input. To learn more about T4, you can visit this link.

Entity types

While self-tracking entities code is generated using the same mechanisms as the default code generation, it takes advantage of the new support for Persistence Ignorance in Entity Framework, and therefore the code generated does not contain any attribute or type defined by Entity Framework. Thanks to this, entities generated by Self-Tracking Entities Template can be used in Silverlight 3. We will describe how to use self-tracking entities in Silverlight in an upcoming walkthrough.

You can browse the Person.cs file under Blogging.Types.tt to get an idea of what it involves.

Untitled

A few things to notice in this code:

  1. There is a DataContract attribute with IsReference = true on each entity type, and all public properties are marked as DataMember. This allows WCF to serialize bidirectional graphs with cycles.
  2. TrackableCollection is a collection type based on ObservableCollection that is also included in the generated code and has the ability to notify each individual change produced in the collection. Self-tracking entities use this type for collection navigation properties. The notification is used for change tracking purposes but also to align various elements that represent the same relationship when any of them changes. For instance, when a Blog is added to a Person’s Blogs collection, the Blog’s Owner reference is also updated to point to the right Person, and the OwnerID foreign key property is updated with the ID of the Owner.
  3. The ChangeTracker property provides access to the ObjectChangeTracker class that stores and controls change tracking information for the entity.

To make it possible to obtain instances of self-tracking entities on the client, we are going to share the code for the types themselves between the service and the client.

Note: Self-tracking entities are not well suited for applications in which sharing the entity types between the client and the server is not possible or practical, like cases in which you only control either the client or the service, but not both. When developing applications for distributed environments in which sharing the types is not possible, consider a solution based on ADO.NET Data Services or custom Data Transfer Objects. Entity Framework’s API can be used to build custom N-Tier solutions. For more information, see here .

As part of this walkthrough we are going to move the code generated for entity types (under Blogging.Types.tt) and the code that is part of the persistence layer (under Blogging.Context.tt) into separate assemblies.

As a first step, we are going to turn off code generation for the templates inside BloggingModel: select the Blogging.Types.tt file on the Solution Explorer. You should now be able to see a property named “Custom Tool” in the Properties window (press F4 if the Properties window is not visible).

 

Untitled

Remove the value “TextTemplatingFileGenerator” and leave it blank. Also, notice that some generated code files under this template are not removed automatically. You will need to expand the tree of generated files under the template and delete them.

Untitled

Then, repeat the operation with Blogging.Context.tt: remove the Custom Tool value and manually delete any remaining generated files underneath.

We are now going to need a new Windows Class Library project to accommodate the entity types. Right click on the solution and add a new class library project using Visual Studio and name it BloggingEntities.

Untitled

Note: You can remove the default Class1.cs file that is automatically added to the project. We are not going to use it in this walkthrough.

Next, we are going to add the template for types to the new BloggingEntities project: right click on the BloggingEntities project and select “Add | Existing Item…”.

Browse for files in the BloggingModel project (you may need to go one level up to see it, and then specify All Files (*.*) as the filter).

Untitled

 

 

 

Select Blogging.Types.tt in the dialog, and on the drop down button at the bottom of the dialog, select the option “Add As Link”.

Untitled

When you add an item to a project as a link, the actual contents of the item are maintained in the location indicated by the original project. This is important because by default the TT file needs to be located alongside an EDMX file in order to obtain all its metadata. However, in the case of T4 templates, links to generated code files are also added to the current project and their contents compiled to the output assembly as well. Since the link is specified using relative paths, the ability to locate the EDMX file is preserved if you move the solution to another directory or in source control.

Note: there are two main ways to move or share the code generated by an Entity Framework T4 template to a different project:

  1. Remove the custom tool in the original location and then add a link to the template in a different project.
  2. Move the template to a different project and then edit the template file to specify a relative path to locate the EDMX file.

In this walkthrough we are going to use the first method.

If you try compiling the BloggingEntities project now, you will see a big number of errors. The reason is that self-tracking entities use DataContract attributes defined in the WCF libraries, which are not referenced by default. Add a reference to the System.Runtime.Serialization library as shown below:

Untitled

Service project

The initial version of the service project contains the service interface definition and basic code for the service implementation. We will be completing and removing commented lines from different parts of the source code until we have a functional WCF service.

Untitled

The three first things the service is going to need are:

  1. The EDM metadata for the Blogging model.
  2. The CLR types for the entities.
  3. The code for the persistence layer (for the sake of brevity we are not going to create a separate assembly for the persistence layer, nor a full blown Repository abstraction).

Metadata

Since the BloggingModel project contains the EDMX file, the output assembly will by default contain the necessary metadata as embedded resources. In order to make the metadata available to the service, we can simply add a project reference on BloggingService pointing to BloggingModel.Untitled

For the Entity Framework runtime to find the metadata, it is necessary to provide the location (in this case a path that points to the embedded resources) in the connection string.

An appropriate connection string is already included in the service’s web.config file, so you won’t need to add it:

 <connectionStrings>
<add name="BloggingContainer" connectionString=
"metadata=res://*/Blogging.csdl|res://*/Blogging.ssdl|res://*/Blogging.msl; provider=System.Data.SqlClient;provider connection string=&quot; 
Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\Blogging.mdf; 
Integrated Security=True;User Instance=True;MultipleActiveResultSets=True&quot;" providerName="System.Data.EntityClient" />
</connectionStrings>

Entity Types

As explained previously, we are going to share the entity types between the service and the client. We do that by adding a reference to the BloggingEntities class library project.

Untitled

Persistence layer

The persistence layer is going to be composed of the derived ObjectContext type generated by the Blogging.Context.tt file. Add a link to Blogging.Context.tt on the BloggingService project following the same procedure we used previously to add a link to the Blogging.Types.tt template to the BloggingEntities project.

Untitled

 

As before, remember to add it as a link:

Untitled

Important: In order to get the namespace of the code generated by this template to match the namespace of the code generated by the Blogging.Types.tt template, we will need to set the value of its “Custom Tool Namespace” property to “BloggingEntities”.

Untitled

 

Service interface

The service interface is contained in the IBlogging.cs file. The interface defines four methods:

  1. Post GetPostWithComments(int PostID): retrieves a Post object by its ID, including all the Comments related to that post.
  2. Void UpdatePostWithComments(Post post): provides the capability of persisting changes to a particular post, including a collection of its related Comment objects.
  3. GetATestPostID: retrieves an arbitrary PostID existing in the database for testing purposes.
  4. GetATestPersonID: retrieves an arbitrary PersonID from the database for testing purposes.

To continue with the walkthrough, un-comment the code contained in IBlogging.cs.

Service implementation

The service implementation is contained in the Blogging.svc.cs file. GetPostWithComments, GetATestPostID and GetATestPersonID are just regular methods that return results of a query through the service operations.

The only thing that is new about these methods with respect to anything you could previously do with Entity Framework is that they return graphs of self-tracking entities instead of regular entities.

We are now going to focus on the most interesting operation, UpdatePostWithComments, which leverages self-tracking entities in order to save changes that have happened to the object graph on the client.

In order to proceed, uncomment all the commented code in Blogging.svc file.

Update method

This method takes a self-tracking Post entity, passes it through to validation logic, and then applies the changes contained in the object graph to the ObjectContext. Finally, it tries to save the changes to the database.

 public void UpdatePostWithComments(Post post)
{
    ValidateUpdate(post);
    ApplyDefaults(post);
    using (var context = new BloggingContainer())
    {
        context.Entries.ApplyChanges(post);
        context.SaveChanges();
    }
}
Validation

You should always validate the input of the update method. For that reason, the sample in this walkthrough demonstrates how to perform some basic validation that restricts the kind of changes that the self-tracking entities can perform.

 private static void ValidateUpdate(Post post)
{
    ValidateCondition(
        post.ChangeTracker.State != ObjectState.Deleted,
        "Deleting a post is not allowed");
    ValidateCondition(
        post.ChangeTracker.State != ObjectState.Added,
        "Adding a post is not allowed");
    ValidateCondition(
        post.ChangeTracker.State == ObjectState.Unchanged || 
        !string.IsNullOrEmpty(post.Body),
        "Empty posts are not allowed");
    ValidateCondition(
        post.ChangeTracker.State == ObjectState.Unchanged || 
        !string.IsNullOrEmpty(post.Title) ,
        "Empty posts titles are not allowed");
    ValidateCondition(
        !post.Comments.Any(c => c.ChangeTracker.State != ObjectState.Unchanged && 
        string.IsNullOrEmpty(c.Body)),
        "Empty comments are not allowed");
    ValidateCondition(
        !post.Comments.Any(c => c.ChangeTracker.State != ObjectState.Unchanged && 
        string.IsNullOrEmpty(c.Title) ),
        "Empty comment titles are not allowed");
}

 

Essentially, this method will throw an exception if any of the following conditions occur:

  1. The blog post contains an empty body or title.
  2. Any of the comments contain an empty body or title.
  3. The client is trying to add a new post or delete an existing post (the UpdatePostWithComments operation is constrained to only allow updates on posts).
Defaults

The next method invoked by UpdatePostWithComments is ApplyDefaults, which sets the ModifiedDate and CreatedDate on Posts and Comments as appropriate. This kind of method is useful if you expect client code not to do that part of the work.

 private void ApplyDefaults(Post post)
{
    var now = DateTime.Now;
    post.ModifiedDate = now;
    foreach (var comment in post.Comments)
    {
        switch (comment.ChangeTracker.State)
        {
            case ObjectState.Added:
                comment.CreatedDate = now;
                comment.ModifiedDate = now;
                break;
            case ObjectState.Modified:
                comment.ModifiedDate = now;
                break;
        }
    }
}
ApplyChanges

At the core of UpdatePostWithComments, we are using the ApplyChanges extension method that has been generated into the Blogging.Context.Extensions.cs file.

The goal of ApplyChanges is to examine the change tracking information contained in the graph of self-tracking entities to infer the set of operations that need to be performed to reflect the changes in the database.

Basic console client

Included in the solution, there is a very simple console application that is used to test operations on the service. The BloggingConsole project will need two things to operate:

  1. CLR types for entities.
  2. A service reference to BloggingService.

It is worth mentioning that the client doesn’t need EDM metadata at runtime: most of the behaviors that Entity Framework would regularly derive from the metadata are already hardcoded in the entity types.

Adding the entity types

The same way we did it on BloggingService, we can just add a project reference to BloggingEntities in order to get the definition of the types on the client.

Untitled

Adding the service reference

Important: Before you can actually add the service reference, you will need to make sure the service project is built. Otherwise, WCF design-time tools will fail to obtain the service’s metadata. Right click on the BloggingService project entry in the Solution explorer and choose the Build menu item.

Once built, you can proceed to add a standard Service Reference to BloggingService on the BloggingConsole project:

Untitled

When configuring the service reference, specify BloggingService as the namespace. You will need to use the Discover button to find the service exposed by the BloggingService in the same solution.

Untitled

 

 

Since the types of the entities are already known, WCF design-time tools will only add the minimum code necessary for the service interface and for the service client.

Self-Tracking Entities extension methods

Before we proceed to look at the usage of self-tracking entities on the client tier, it is opportune to review some of the ways you can control self-tracking entities. The following are extension methods can be applied to any self-tracking entity:

  • StartTracking: instructs the change tracker on the entity to start recording any change applied to the entity. This includes changes on scalar properties, changes on collections and references to other entities. It is usually unnecessary to invoke this method on the client tier, because self-tracking entities start tracking automatically when they are de-serialized into the client through WCF. An entity that is directly created in code (i.e. using “new”) on the client won’t track changes until either StartTracking is invoked or it is connected through a navigation property to another self-tracking entity that is already tracking changes.
  • StopTracking: instructs the change tracker on the entity to stop recording changes. This method comes handy when it is necessary to manipulate the graph of self-tracking entities without causing changes to be later persisted to the database. For instance, to simulate an “attach” operation on a collection it is possible to stop tracking changes on both end, the call the Add method on the collection, and the resume tracking on both ends with StartTracking:
 post.StopTracking();

comment.StopTracking();

post.Orders.Add(comment);

post.StartTracking();

comment.StartTracking();
  • MarkAs[State]: Modifying the value of a property on a tracking entity will put it in the modified state, but some operations require explicitly changing the state of an entity. For this purpose, four convenience extension methods facilitate changing the state of an entity explicitly to Added, Modified, Deleted or Unchanged. The default state for a newly created entity is added. The MarkAs[State] methods return the same entity they are applied to, with the new state applied to it, therefore facilitating the use of the methods inline:
 post.Author = new Person { ID = authorID }.MarkAsUnchanged();
  • AcceptChanges: this method clears the change tracking information for an entity and moves its state to Unchanged.

Testing methods on the client

In order to proceed with the walkthrough now, uncomment the methods on the file Progam.cs, which contains some simple scenario tests for the service. The program follows this sequence:

  1. An existing PostID and a PersonID are obtained from the service.
  2. Retrieve the post corresponding with PostID.
  3. Add a new comment to the post, and save it through the UpdatePostWithComments service operation. The author for the comment is the person corresponding to PersonID.
  4. Delete all comments for the post and persist this change through the UpdatePostWithComments.
  5. Also, the post is retrieved and displayed in the console at various stages.

Notice that each separate method creates and disposes its own instance of the service client, just for the purpose of testing operations independently.

Executing the program

You can learn a lot more about self-tracking entities while stepping through the Console program and by making adjustments to the code. Make sure you right click on the BloggingConsole project entry on the Solution Explorer and then choosing the “Set as StartUp Project” menu item.

Here is the default output of the program when you execute it:

 

Untitled

Adding comments

One of the most interesting methods here is AddComment:

 private static void AddComment(int postID, int authorID, string title, string body)
{
    using (var service = new BloggingClient())
    {
        var post = service.GetPostWithComments(postID);
        var author = new Person { ID = authorID }.MarkAsUnchanged();
        post.Comments.Add(new Comment { Author = author, Title = title, Body = body });
        service.UpdatePostWithComments(post);
    }
}

The method follows this sequence:

  1. Creates an instance of the service client within a using statement.
  2. Retrieves a blog post from the service using GetPostWithComments.
  3. Create a new Person entity called author. This entity is what is often called a “stub”, since it is only going to represent the identity of a Person that already exists in the database.
  4. Add a new Comment to the Post, by filling the author, title, and body.
  5. Send the proposed change to the service through UpdatePostWithComments.

Note: Newly created self-tracking entities are marked as Added by default. The stub entity of type Person used in this method is moved to the Unchanged state explicitly with the MarkAsUnchanged extension method. Unless we do this, when ApplyChanges back on the service will specify that this is a new Person that needs to be added to the database. Then, SaveChanges will fail while trying to insert a row with a duplicate key.

Using Foreign Keys

The use of a stub entity described above is a common pattern used in Object/Relational Mappers. Since Entity Framework now supports foreign keys, there is an alternative way to relate the Comment with its Author: provided we know the primary key value of the Person that we want to assign as an author, we can set the value to the AuthorID property in the Comment. Using foreign keys the method above would change to this:

 private static void AddComment(int postID, int authorID, string title, string body)
{
    using (var service = new BloggingClient())
    {
        var post = service.GetPostWithComments(postID);
//      var author = new Person { ID = authorID }.MarkAsUnchanged();
        post.Comments.Add(new Comment { AuthorID = authorID, Title = title, Body = body });
        service.UpdatePostWithComments(post);
    }
}

 

With foreign keys, stub entities become unnecessary. In any case, self-tracking entities can use both foreign key associations and independent associations as they appear in the model.

Deleting comments

Another interesting method to look at is DeleteAllComments:

 private static void DeleteAllComments(int postID)
{
    using (var service = new BloggingClient())
    {
        var post = service.GetPostWithComments(postID);
        foreach (var comments in post.Comments.ToArray())
        {
            comments.MarkAsDeleted();
        }
        service.UpdatePostWithComments(post);
    }
}

The method follows this sequence:

  1. Creates an instance of the service client within a using statement.
  2. Retrieves a blog post from the service using GetPostWithComments.
  3. Marks each comment for the post as Deleted.

Note: the foreach loop is performed over a copy of the original collection of comments. This has to be the case because MarkAsDeleted will remove the entity from the collection, and modifying the enumeration over which foreach is looping would cause an exception.

Testing validation

If you want to test how the server-side validation behaves, you can try passing an empty string for title or the body of a comment, by adding a line like this:

 AddComment(postID, authorID, "Bad post", "");

 

Summary

The walkthrough has described basic usage of the Self-Tracking Entities feature. We hope you have learned enough about how to use self-tracking entities that you can experiment with the Feature CTP 2 version on your own code.

There are some areas in which we expect to be improving self-tracking entities in the final release of Visual Studio 2010. Please let us know of any issues you find.

Additional notes

Why not POCO Proxies

Alongside POCO support, we added the capability to create dynamic proxies for entities that comply with certain requirements. Self-tracking entities do not make use of this feature for several reasons:

1. Self-tracking entities are optimized for serialization scenarios, and dynamic proxy types complicate WCF serialization. Before serializing, we would need to take advantage of WCF interception mechanisms to “convert” the instance to serialize back to the original POCO types.

2. One of the characteristics of POCO Proxies is their ability to perform lazy loading. Using serialization and lazy loading together requires much care, since lazy loading may cause unintended data to be queried and included in the graph.

3. In the main scenario we are trying to address in this release, most changes happen on the client side. While change tracking proxies optimize change tracking performance, that only happens when the entities are being tracked by the ObjectStateManager. The default snapshot-based change tracking mechanism used for pure POCO objects provides enough functionality for self-tracking entities.

Database generation scripts

If you need to create the database outside the project, you will find database creation scripts in the App_Data folder of the BloggingService project.

 

EFFeatureCTP2_Walkthrough_STE.ZIP

Comments

  • Anonymous
    June 22, 2009
    Thank you for submitting this cool story - Trackback from DotNetShoutout

  • Anonymous
    June 23, 2009
    Very nice walkthrough. Do you have a similar one for ASP.NET?

  • Anonymous
    July 14, 2009
    Is it safe to assume there won't be a change tracking solution that is interoperable with non-clr technologies in EF 4.0?  An example would be serializing to JSON for use with the new Ajax features in asp.net 4.0, or even when consuming these services through Java or AS3. Everything in the EF 4.0 has been really impressive thus far, but losing interoperability(one of the main advantages of using web services in the first place in my opinion) would be unfortunate. Regardless, thanks for all the updates, they're very helpful.

  • Anonymous
    July 21, 2009
    @Steve: While we haven't attempted to provide an end to end solution in which the client runs in JavaScript or on some other platform, it is one of our design goals to keep the “public surface”  of self-tracking entities as simple as possible to enable other implementations:

  • On one side, the serialization payload that is produced with the classes we generate is very clean and I can imagine it would be possible to consume and produce it relatively easily from any client.
  • On the other side, if you want to provide your own entity types and serialization, you can think of implementing the adapter interface that the ApplyChanges method takes as the second parameter. Given the current implementation, however, if you just wanted to directly use JSON, there is a known issue with DataContract’s IsReference = true. We will keep these things in mind for our next refresh.
  • Anonymous
    July 21, 2009
    Manfred, I noticed that you are not using WCF, all operations are happening on the server side. In this case, you must turn on ChangeTracking manually in your main() after retrieval: Category c = dao.findById(1);                                c.ChangeTracker.ChangeTrackingEnabled = true; Note that if your dao actually go through WCF serialization, ChangeTracking will be turned on by default.

  • Anonymous
    July 22, 2009
    Once I move Blogging.Types.tt to BloggingEntities, I don't get generated files underneath it. It has been added as a link I've tried build and RunCustomTool.  The latter produces nothing in the output window either?? It's configured as TextTemplatingFileGenerator.  Custom Tool Namespace was blank - I made it BloggingEntities The Blogging.Context.tt in BloggingService does work Any ideas? Thanks Martin

  • Anonymous
    July 22, 2009
    I notice the final step version of the project (which does work) shows the generated files as linked. Back to the initial project - if I click the "transform all templates" button I get Transforming templates for all project items.


Transforming template Blogging.Context.tt with TextTemplatingFileGenerator ... succeeded. Transforming template Blogging.Types.tt with TextTemplatingFileGenerator ... succeeded.

Text templating transformation complete In fact the files have been generated (in the same directory as the corresponding tt file). They just aren't linked in for the types tt file.  I don't know why they link ok for the context tt file. Martin

  • Anonymous
    July 25, 2009
    The comment has been removed

  • Anonymous
    July 28, 2009
    It looks like the process you're recommending requires the use of CLR types on the client.  How are you recommending that we use this approach with Silverlight clients?  I suppose we can implement our own tracking from scratch (as you seemed to recommend above), but that doesn't seem to be terribly efficient, and it certainly makes Silverlight a second-class citizen relative to the rest of the MS universe.  Are you planning to include self-tracking entity generation with the SLSvcInst.exe proxy generation tool?

  • Anonymous
    July 29, 2009
    I've noticed that with the Self Tracking Entities, when the ObjectContext's SavingChanges event is fired, the ObjectStateManager.GetObjectStateEntriesObjectStateManager.GetObjectStateEntries(System.Data.EntityState.Modified) returns an empty list when there are modifications that actually do get persisted.  I want to be able to trap whenever and however an Entity is being saved. Is there another method I can employ to do this with the Self Tracking Entities? Thanks.

  • Anonymous
    July 29, 2009
    @Todd: Please, try invoking the context's DetectChanges() method before GetObjectStateEntries(). Self tracking entities are POCO objects without change notification, therefore it is necessary to push the changes from the object graph to the ObjectStateManager before invoking any API that requires having the ObjectStateManaer up to date.

  • Anonymous
    July 29, 2009
    @Ken: tracking of changes on the client depends on the change tracking logic embeded in the entity types. Our current impementation has a couple of source code incompatibilities with the Silverlight version of the CLR and BCL, but we will work on that. We don't have plans to generate self-tracking entities as the default for WCF clients. Also, if you need a rich application framework for Silverlight that works with Entity Framework, you may want to try .NET RIA Services.

  • Anonymous
    July 29, 2009
    @Martin: Yes, the way I did the walkthrough I basically leave the original copy of the TT files in the same project as the EDMX file because the TT file needs to find the EDMX file in a relative path (although you can override the exact location by editing the TT file). Then I "add as linked" the TT files wherever I need them and that should automatically bring the linked generated files. I am not sure what can go wrong, but I guess my first recommendation if that doesn't happen is to revert things to the previous step (i.e. remove the linked TT file) and add it again. Hope this helps, Diego

  • Anonymous
    August 04, 2009
    Hi, I'm trying to persist an object graph across the service.  The object graph looks like this: Course |- Professor Professor |- List<Student> Students When I change the Professor through databinding in WPF, the Course.ChangeTracker contains a reference to the original Professor in the OriginalValuesForReferenceProperties collection.  I use the ApplyChanges() method on the data context service side, and the first update works fine.  But if I change the Professor again, the SaveChanges() method of the data context says there is a duplicate key.  The Course.ChangeTracker also still maintains its original reference to the first Professor, which I am assuming is causing the duplicate key violation, but I can't seem to reset the ChangeTracker client side.  If I call Course.MarkAsUnchanged() on the client, the old Professor reference still remains.  My service call returns void, just like the examples above... but I've seen other people returning the same object after the database update.  Anyone having similar problems?

  • Anonymous
    August 08, 2009
    @ncloud: can you please explain what do you mean with "if I change the Professor again"?

  • Anonymous
    August 15, 2009
    Hi, really a great Job! I start to use this functionality for a new application! Stay tuned!!! Uwe

  • Anonymous
    September 14, 2009
    i can't get it work for me. I gave two related tables: Product and ProductCategory, and three WCF methods: GetProduct, GetCategory and UpdateProduct. If i'm changing simple properties of Product, it works fine, but if i'm assigning like this: product.ProductCategory = wcfClient.GetCategory(catId) and call UpdateProduct, it throws exception. From other side it doesn't work either, if I'm doing like productCategory.Products.Add(product) and call product category update, it falls with exception also.

  • Anonymous
    October 19, 2009
    The comment has been removed

  • Anonymous
    October 20, 2009
    Hi, is this functionality still available under Beta2 and later in the final release? Thanks a lot!

  • Anonymous
    November 04, 2009
    One question, i have a web service that return a System.Data.Entity.DynamicProxies and occur error this class is not serializable, what i can do????

  • Anonymous
    November 06, 2009
    Hi Julio, I think I already responded to you in the forums, but for the benefit of others that might hit this page: this is a known issue. The solution is not included in beta 2, but he workaround is to temporarily disable the creation of proxies when you are returning entities that you plan to return from the service. Use context.ContextOptions.ProxyCreationEnabled = false. Hope this helps, Diego

  • Anonymous
    November 06, 2009
    @uns_uwe: Hi, an updated version of the CTP that is compatible with beta 2 has been released. You can find the announcement here: http://blogs.msdn.com/adonet/archive/2009/11/04/ado-net-entity-framework-community-technology-preview-released.aspx

  • Anonymous
    November 08, 2009
    How do I create self-tracking poco objects. I can only select one of the two templates.

  • Anonymous
    November 11, 2009
    Nice work. If this works out Ill be excited to delete piles of code! This actually has quite a bit of value in regular asp.net or mvc.net. With self tracking entities customers can use clean testable patterns (controllers, repos, pocos) and steer clear of the EntityDataSource. Whats up with these names though :) FixupChangeTrackingCollection EntityChangeTrackerAdapter Also, is it neccesary to specify EntityChangeTrackerAdapter.GetSelfTrackingEntityInfo when saving? If your applying changes shouldnt it be implicit that you need to get the GetSelfTrackingEntityInfo?


context.Entries.ApplyChanges(            post,            EntityChangeTrackerAdapter.GetSelfTrackingEntityInfo);

  • Anonymous
    November 15, 2009
    @Steve: The entity types the Self-Tracking Entities Template produces are POCO objects in the sense that they don't have a dependency with Entity Framework, but of course they include additional code to track changes. The goal of the POCO Template (which by the way is not included in the Feature CTP 2) is to produce simple types that can work as entities in Entity Framework. With the current approach we can’t support functionality like ApplyChanges without the additional code in self-tracking entities, so you will need to choose among the two depending on whether this functionality is important for your application. Hope this answers your question, Diego

  • Anonymous
    November 15, 2009
    @Jarod: Thanks for the feedback on this! In the updated version of the Self-Tracking Entities template included in the Feature CTP2 we changed the implementation of collections quite a bit. The new collection type is called TrackableCollection and is based on ObservableCollection. Besides, we were able to remove the second parameter of the ApplyChanges method as now the template actually generates the code for ApplyChanges and then we can make it depend on the entity types. We have also paid more attention in general to names and to the code we generate, although there are still a few things we are still planning to improve before RTM. Thanks, Diego

  • Anonymous
    November 15, 2009
    Hi   I'm trying the self tracking entities and i have notice that when we call the method  entity.AcceptChanges() it doesn't propagate the AcceptChanges to the child entities and when we make changes to a child entity the parent entity isn't warned that something has changed, is this normal behaviour or is it bug?  Also is it possible to have a method  HasChanges() in the entity. Many thanks JC

  • Anonymous
    November 20, 2009
    Hi If anyone is interested this is my version of the AcceptChanges(): public static void AcceptChanges(this IObjectWithChangeTracker trackingItem)        {            if (trackingItem == null)            {                throw new ArgumentNullException("trackingItem");            }     Type t = trackingItem.GetType();                PropertyInfo[] props = t.GetProperties();                foreach (PropertyInfo p in props)                {                    if (p.PropertyType.Name == "TrackableCollection`1")                    {                        IList list = (IList)p.GetValue(trackingItem, null);                        foreach (IObjectWithChangeTracker b in list)                        {                            b.ChangeTracker.AcceptChanges();                        }                    }                }            trackingItem.ChangeTracker.AcceptChanges();        } Regards JC

  • Anonymous
    November 20, 2009
    Where can I find any discussion which might be going on regarding the future of self-tracking entities and ASP.NET web forms?   Currently, to update a small number of fields for an entity using a web form I choose to re-query my BL, allow ASP.NET to update the bound fields, pass the updated entity to my BL, and apply changes (including FKs).  Before I get carried away I would really like to know when I might expect to be better off using self-tracking entities. (MVC is not in my future.) Also, being my first ever contact with the team I wanted to thank Diego, Danny, Alex and the whole Entity Framework team for what you have done. You had my vote of confidence the day I read about EF, when I understood the big picture which some people were too close (to their own product) to see. Keep up the pace of development and you'll continue to earn the respect you deserve. Graham

  • Anonymous
    November 21, 2009
    Hello Graham, Your kind words are appreciated. I will transmit your message to the team. We identified a scenario in in ASP.NET WebForms in which self-tracking entities could be very useful. I think this might be the scenario you are referring to: preserving graphs of entities with changes in ASP.NET state management objects (i.e. Session or ViewState) across postbacks. The main obstacle to use self-tracking entities in this way is that STEs don’t support binary serialization. There are workarounds for this, like serializing with a DataContractSerializer into a memory stream, but we still haven’t worked in a pattern that we can recommend. In many Web scenarios you usually modify one entity. If that is your case, you can probably use the approach that Danny explains here: http://blogs.msdn.com/dsimmons/archive/2008/10/31/attachasmodified-a-small-step-toward-simplifying-ef-n-tier-patterns.aspx This approach works great with the new support for FKs, because FKs are now structurally part of the entity so relationships get affected by the method. Finally, you can consider using the EntityDataSource, which makes doing CRUD operations with Entity Framework very easy in ASP.NET WebForms applications. Although from your description of the scenario it seems that you have better layer separation. Hope this helps, Diego

  • Anonymous
    November 23, 2009
    Hi to all, i have a problem with Self-Tracking Entities: method DeletePerson not works,but DeletePersonTwo works , why???. It looks the same public class PersonAD {   public void DeletePerson(int ID)   {     using(BloggingContainer ctx = new BloggingContainer)     {        Person p = (from p in ctx.PersonSet                            where p.Id == ID                            select p).First();       person.MarkAsDeleted();       ctx.PersonSet.ApplyChanges(person);       ctx.SaveChanges();     }   }   public void DeletePersonTwo(int ID)  {     using(BloggingContainer ctx = new BloggingContainer)     {       Person p = this.GetPerson(ID);       person.MarkAsDeleted();       ctx.PersonSet.ApplyChanges(person);       ctx.SaveChanges();     }  }   public Person GetPerson(int ID)   {        using(BloggingContainer ctx = new BloggingContainer)     {        Person p = (from p in ctx.PersonSet                            where p.Id == ID                            select p).First();       return p;   }   } }

  • Anonymous
    November 23, 2009
    Sorry,some mistakes in writing at first, but the same question again: method DeletePerson not works,but DeletePersonTwo works , why???. It looks the same public class PersonAD {   //NOT works   public void DeletePerson(int ID)   {     using(BloggingContainer ctx = new BloggingContainer())     {        Person personToDelete = (from p in ctx.PersonSet                                 where p.Id == ID                                 select p).First();       personToDelete.MarkAsDeleted();       ctx.PersonSet.ApplyChanges(personToDelete);       ctx.SaveChanges();     }   }  //Works  public void DeletePersonTwo(int ID)  {     using(BloggingContainer ctx = new BloggingContainer())     {       Person personToDelete = this.GetPerson(ID);       personToDelete.MarkAsDeleted();       ctx.PersonSet.ApplyChanges(personToDelete);       ctx.SaveChanges();     }  }   public Person GetPerson(int ID)   {        using(BloggingContainer ctx = new BloggingContainer())     {        Person myPerson = (from p in ctx.PersonSet                            where p.Id == ID                            select p).First();       return myPerson;   }   } }

  • Anonymous
    November 23, 2009
    Hi Droje Dar I think that you must attach de entity to the context prior to the deleting: try something like this using (TransactionScope tx = new TransactionScope())                {                    using (BloggingContainer ctx = new BloggingContainer ())                    {                        ctx.AttachTo("PersonSet", entity);                        ctx.PersonSet.DeleteObject(entity);                        ctx.SaveChanges();                    }                    tx.Complete();                } Regards JC

  • Anonymous
    November 23, 2009
    How would this work with MVC? If the controller passed the self tracking entity to a strongly typed view, the entity would be lost when the form is submitted as all we have then is the submitted values. This is unless we store the original entity somewhere such as the Session and then retrieve it when the values are posted to the Controller. This seems ugly and not scalable to me.

  • Anonymous
    November 24, 2009
    Hi, I've noticed a bug in the ChangeTracker. When I call the SaveChanges method after I saved new entities, the ObjectState of the ChangeTracker is still "Added" and not UnChanged as expected. Any idea why? or how can I simply resolve it instead of coding additional background code? Thanks, Yaniv.

  • Anonymous
    December 02, 2009
    Hi,  Can anyone point me in a direction to get a list of the properties that have changed?  I can't seem to find the original values on my objects.  the OriginalValues collection count is always 0 even when one of my properties is changed.   thanks, Melinda

  • Anonymous
    December 08, 2009
    How does this work with Data Services. What do I put in  DataService<> Thanks, David McCarter

  • Anonymous
    December 08, 2009
    Also, in my ADO Data Service project, it won't let me add the context file as a link. Any ideas why?? David

  • Anonymous
    January 03, 2010
    I have experimented with persisting the state of the Entity/Object Graph in asp.net Session Sate Object across posts... it seems to work fine with or without Serializing it first utilizing the DataContractSerializer. Am I missing something? from : mark.henke@hotmail.com

  • Anonymous
    January 04, 2010
    @Mark: by default ASP.NET manages state in-process, and therefore the is actually no serialization involved. In out-of-process mode, however, ASP.NET will use the binary formatter, which self-tracking entities currently don't support directly. Therefore, if you are absolutely sure that for your application ASP.NET state management is always going to be in process, it might be ok to use STEs in this way.

  • Anonymous
    January 05, 2010
    thx diego! I am testing it out now using ASP.net StateServer mode. With webgarden option=true, CPUMask="1111" in the machine.config as well. had to utilize the the DataContractSerializer to convert the graph to bytes as you described earlier in the post. any further progress on this topic in your end?

  • Anonymous
    January 21, 2010
    the types.tt moved into a BloggEntities when you are using WCF Service Library instead of WCF Service Application is not working, the contex.tt work but the types.tt now, why? Your example works but if you use a WCF Library and move the types.tt in other proyect, im getting the error "Unable to load the specified metadata resource" I tested with WCF Service Application works fine, but with WCF Service Library dont work, why?

  • Anonymous
    February 08, 2010
    Why can't I use: context.Entries.ApplyChanges I only see the old methods?

  • Anonymous
    February 11, 2010
    Been playing with the CTP2 version of self-tracking entities for a while. I really like it - great job guys. There are however a couple of tweaks/bug fixes I had to make to get it working as expected.

  1. Same problem/bug as witnessed by Droje Dar's post above. Basically, the reason DeletePersonTwo works is because of the nested BloggingContainer context which essentially means that by the time ctx.PersonSet.ApplyChanges is called, personToDelete is a DETACHED object (cause nested context is out of scope).   The real problem here is that after you've made a change to an entity and you've saved the changes, any further attempts to modify this entity WHILE it's still attached to the same context will have no effect. The easy fix I've done in my implementation of ApplyChanges is to simply detach the entity before invoking the ApplyChanges functionality - i.e. public static void ApplyChanges<TEntity>(this ObjectSet<TEntity> objectSet, TEntity entity) where TEntity : class, IObjectWithChangeTracker        {            if (objectSet == null)            {                throw new ArgumentNullException("objectSet");            }            ObjectStateEntry entry;            if (objectSet.Context.ObjectStateManager.TryGetObjectStateEntry(entity, out entry))            {                objectSet.Detach(entity);            }            objectSet.Context.ApplyChanges<TEntity>(objectSet.EntitySet.EntityContainer.Name + "." + objectSet.EntitySet.Name, entity);        }
  2. Minor improvement, but I think the following makes more sense:    [Flags]    public enum ObjectState    {        Unchanged = 0x0, // changed from 0x1        Added = 0x1, // changed from 0x2        Modified = 0x2, // changed from 0x4        Deleted = 0x4, // changed from 0x8    }    Specifically, this will ensure that the state of Unchanged can't co-exist with anything else
  3. I've also augmented my context's SaveChanges method (in my implementation, EF context has been totally encapsulated/abstracted via interfaces etc so this was very easy to do for me...) so that ALL IObjectWithChangeTracker entity states will be reset to unmodified after SaveChanges.   This is actually quite easy to do and much easier than having to remember to call AcceptChanges individually for all nested/relationship entities.   Basically, all you have to do is something along the lines of   var changedEntities = myContext.ObjectStateManager    .GetObjectStateEntries(EntityState.Added | EntityState.Modified | EntityState.Deleted)                    .Where(entry => entry.Entity is IObjectWithChangeTracker)    .AsEnumerable<IObjectWithChangeTracker>();   foreach(var entity in changedEntities)   { entity.AcceptChanges();   }
  • Anonymous
    February 18, 2010
    Gah.  When are you code generator folks gonna learn to globally scope your types in your T3s? https://connect.microsoft.com/VisualStudio/feedback/details/534658/ef4-ctp-generated-code-not-using-globally-scoped-types

  • Anonymous
    February 18, 2010
    Gah.  When are you trolls going to stop calling T4 templates "T3s"?

  • Anonymous
    March 19, 2010
    Nice! In regard to the questions about asp.net. Will MS provide a pattern / implementation in .NET /preferred example for handling self tracking entities in regard to (memory)viewstate / session? This would prevent unneeded select or update db calls and provide a standard for the asp.net forms world. Also still missing the IDataErrorInfo in 4.0 ;)

  • Anonymous
    March 24, 2010
    Thank you for the detailed article. I noticed there were questions regarding implementing using MVC. We have the same issue: I have a strongly typed View that displays an Entity. When the View is submitted by the Client, I rebuild the Entity using the Form values, and call the ApplyChanges method - expecting the changes to be ignored (in case of no changes) or updated. However, the Framework evaluates these to be new values and ends up Adding to the Database. Could you please explain what I should do differently? Thanks,

  • Anonymous
    March 30, 2010
    Can i have something like this Service: Entry GetEntry() { Post p = null; //Computations //fill p with post return p; } Client: Entry e = proxy.GetEntry(); Can this be done? If so, how?

  • Anonymous
    April 18, 2010
    How can you use self tracking entities with WCF if you don't know what your clients are written in?  Seems to me that EF4 is fairly useless in this situation and I will have to tradditional methods.

  • Anonymous
    May 27, 2010
    Has anyone been able to serialize self-tracking objects with the JSON serialization in WCF?  I seem to be able to serialize to XML but I really need JSON for javascript/ajax clients.

  • Anonymous
    January 18, 2012
    I posted a short step through on how to reflect database changes to the entities: www.dailycode.info/.../Entity-frame-work-with-self-tracking-entities-database-changes.aspx