Click here to Skip to main content
Click here to Skip to main content

Reattaching Entity Graphs with the Entity Framework

By , 10 Mar 2009
 

Introduction

One of the main challenges when using the Entity Framework (version 1) is exchanging entity graphs between tiers of a Service Oriented Application.

When using Silverlight for building Rich Internet Applications, or Rich Client Applications with Windows Forms or WPF, it is natural to provide coarse grained services on your service layer. Consider, for instance, a 'Software-as-a-Service' invoicing application written in Silverlight… The server-side invoicing service could provide operations like the following:

  • GetProducts(ProductSelectionCriteria)
  • GetCustomers(CustomerSelectionCriteria)
  • GetInvoices(InvoiceSelectionCriteria)
  • GetSuppliers(SupplierSelectionCriteria)
  • SaveProduct(Product)
  • SaveCustomer(Customer)
  • SaveInvoice(Invoice)
  • SaveSupplier(Supplier)

These service operations allow you to implement the client with a minimum of 'post backs' to the server, which is one of the reasons we like to use Rich Internet Applications.

Unfortunately, we will see that the Entity Framework (version 1, at least) does not support this scenario very well.

Attached/Detached Entities

The Entity Framework, as most ORMs, operates on entities under its management. Whenever an EF query is executed (and MergeOption is not set to NoTracking), the instantiated entities are 'attached' to the EF context.

This means that whatever happens to those entities (their properties and relations are changed), the Entity Framework will be aware of it and will be able to save those changes.

However, when an entity is sent to a different tier, it leaves the Entity Framework context, and becomes 'detached'. Whatever changes are done to the entity in the detached state, no EF context will be aware of those changes, and will not be able to save them.

The solution sounds obvious, but is unfortunately not that simple: reattach the entity to an EF context before saving it…

Although this sounds easy, the implementation of the Entity Framework (version 1) does not allow us to attach an entity graph containing both new and changed entities. Basically, the ObjectContext class of the Entity Framework provides two methods to (re)attach entities:

void AddObject(string entitySetName, object entity)
void Attach(IEntityWithKey entity)

The first method, AddObject, is to be used exclusively to attach new instances to an Entity Framework context. For instance, if the invoicing application creates a brand new invoice, it would be able to attach it to a context using the AddObject method. Or not… as we'll see later.

The second method, Attach, is to be used exclusively for entities that already exist on the context, and only need to be attached. For instance, if the invoicing application retrieves an existing invoice, edits it, and then wants to save the changes, it would need to use the Attach method to attach the edited invoice before saving it.

Both methods, AddObject and Attach, are able to copy with object graphs, and, to some extend, even with object graphs containing a mix of new and attached entities.

However, none of those methods are able to handle a mix of attached and detached entities. And, this is a real issue if you understand that it means it is impossible to bring a set of two related detached entities in attached state, since as soon as one of those objects gets attached, you have a situation of an attached entity linked to an unattached entity.

The Entity Framework will not allow you to have an attached entity linked to a detached entity, even during transition phases. As a reaction, the Entity Framework will either throw an exception, or simply cut the link between your objects…

System.InvalidOperationException: The object cannot be added to the ObjectStateManager because it already has an EntityKey. Use ObjectContext.Attach to attach an object that has an existing key..

Basically, this means the Entity Framework cannot (re)attach to object graphs, and most scenarios where detached entities are to be reattached to be persisted by the Entity Framework will not work.

For instance:

  • Creating a new invoice will not work: the new invoice instance will be linked to an existing (but detached) customer instance. The same will be true for the invoice lines, which will be linked to existing product instances. Calling ObjectContext.AddObject will result in an InvalidOperationException.
  • Editing an existing invoice will not work (1): the invoice and invoice lines form a graph of objects to which detached and new instances can coexist, which is not supported by the Entity Framework.
  • Editing an existing invoice will not work (2): suppose I edit an invoice by removing one of its lines, how will it be detected that an invoice line is to be deleted?
  • Editing an existing invoice will not work (3): I edit and send back an invoice to be saved. The invoice is linked to a customer entity and to invoice line entities. The lines are linked to products, etc. To which extend should the object graph be persisted on the store? Should the relationship between invoice lines and products be persisted? Should the relationship between products and suppliers be persisted? The Entity Framework can guess which relations to persist and which not.

The EntityBag Solution

One solution developed by Danny Simmons (a Development Manager in the Data Programmability team at Microsoft) is the EntityBag (http://code.msdn.microsoft.com/entitybag/). The EntityBag is some kind of object context that can live on the client-side, and will store change tracking information. When the entity bag is sent to the server to be persisted, all changes can then be reproduced on an attached Entity Framework ObjectContext.

Although the EntityBag solves the issues discussed above, this solution also has some issues on its own. First, it requires you to run the Entity Framework on the client side, and is therefore not interoperable with Java or other non-.NET languages. But mainly, you will need to review the signatures of your service operations, you may need more service operations, and, above all, I find the modified service operations not following the very nature of WCF's data contracts.

For instance, if you want your RIA client to retrieve a list of invoices, and then have the opportunity to save an edited invoice, you could define the following operations:

Invoice[] GetInvoices(int customerId)
void SaveInvoice(Invoice editedInvoice)

With the EntityBag solution, you'll have to make sure to obtain an EntityBag on the invoice before starting to edit it, so you'll need an additional operation and an additional postback:

EntityBag<Invoice> GetInvoiceEntityBag(int invoiceId)

The GetInvoices method could remain unchanged, but the SaveInvoice would be changed into:

void SaveInvoice(EntityBag<Invoice> editedInvoiceEntityBag)

Besides the fact that the use of the EntityBag affects our Service Contract, it also introduces the use of Generics, which is not in line with the nature of WCF contracts.

The AttachObjectGraph Solution

The solution I propose in this article, and of which I here provide the code, consists of a single AttachObjectGraph Extension Method on ObjectContext, which can attach object graphs, combining both new and detached instances to a parameterizable extend.

The idea is to have a single AttachObjectGraph method that is smart enough to know how the given object graph is to be attached so that it is usable in all common scenarios.

The AttachObjectGraph method is defined as follows:

public static T AttachObjectGraph<T>(this ObjectContext context,
              T entity, 
              params Expression<Func<T, object>>[] paths
)

The paths argument surely seems awkward. But, as you will see, it provides a very handy and safe way of defining the paths of the graph to be attached.

To demonstrate the use of this method, I will use the following sample model, which is also available for download:

efinvoicesample.png

It's a typical example, but it's an example where most common scenarios come along. The scenarios we can test using this model include:

  • creating a new invoice
  • editing an invoice by changing properties (i.e., InvoiceDate, StateCode, Comments, …)
  • editing an invoice by adding lines
  • editing an invoice by editing lines (i.e., setting a different Quantity or Product)
  • editing an invoice by removing lines
  • changing the supplier of a product

All but the last of these scenarios will be supported by one single implementation of a SaveInvoice (server) operation:

void SaveInvoice(Invoice invoice)
{
    using (var context = new SampleInvoiceContext())
    {
        context.AttachObjectGraph(
            invoice,
            p => p.Customer,
            p => p.Lines.First().Product
        );
 
        context.SaveChanges();
    }
}

The AttachObjectGraph method receives as first argument the (root) entity to attach. In this case, an invoice. The remainder of the arguments (a params array of expressions) represent paths of relations to be included in the attach operation.

In the SaveInvoice operation above, we request to attach an invoice along with (its relation to) its customer, (its relation to) its invoice lines, and their related products. As the Lines property results in a collection, we can't immediately dereference its relational properties. Therefore, a call to the First() method is done. In reality, all lines will be attached. The call to First() is there only to provide code completion support in the editor and compile checking. Alternatively, the call could – if a matching overload would have been provided – be written as follows, in which case, there would be no compile time checking:

context.AttachObjectGraph(
    invoice,
    "Customer",
    "Lines.Product"
);

The SaveInvoice operation will thus attach its given invoice, including its customer, invoice lines, and products. It will, however, not touch the relation a product has with a supplier.

The AttachObjectGraph method solves the following issues:

  • It can attach object graphs containing mixes of detached but existing entities and new entities, and hence solves our main issue.
  • It does not add specific requirements to the Service Contract, and therefore can be applied transparently and fully in the spirit of WCF contracts.
  • It does not require the Entity Framework to run on the client, and hence is not tied to .NET languages. It does, however, require the Entity Framework EntityKey property to roundtrip, which is done automatically by WCF, and can be hidden through the ExtensionDataObject property.
  • It is secured to some level, as you have the guarantee that only entities in the given paths can be manipulated. Additionally, you could perform additional security checks and (business) logic between the call to AttachObjectGraph and SaveChanges.

This means that the AttachObjectGraph method provides a really interesting and powerful way of using the Entity Framework over tiers. Still, with some additional features, the method will be usable in almost any standard case.

Performance

The first version of the AttachObjectGraph method performed lazy loading of relations. Therefore, reattaching an invoice with 10 lines would result in 13 queries being issued to the database (one to get the invoice, one to get the customer relation, one for the lines relation, and 10 more for the product relation of each line). The more lines the invoice had, the more queries were issued to the database.

The AttachObjectGraph method has now been enhanced to perform an automatic preload of the object graph, such that the objects are already in memory when the attach operation is performed. The automatic preload consists of a single query loading the whole stored object graph. The 13 queries are reduced to 1 single query.

Of course, the automatic preload only works for entities and relations already present on the data store. When attaching a newly created invoice, no automatic preload can occur, and several queries will be issued to retrieve the customer and products the invoice is related to.

In most cases, entity graphs are created less often than they are used or manipulated. The automatic preload will therefore increase performance in most cases, while have no extra cost in most other cases.

Although the automatic preload built in the AttachObjectGraph method cannot perform for object graphs where the root entity is new, you could, yourself, knowing the specific situation, perform a 'manual' preload by simply querying the related existing entities in the context, prior to calling the AttachObjectGraph method.

The following code, for instance, 'manually' preloads all products:

var allproducts = from p in context.ProductSet select p;
allproducts.ToArray();

Additional Features

Attaching Collections

The SaveInvoice operation described earlier saves a single invoice. You might also be in a situation where you want to attach a collection of objects to the context. For instance, you might want to save a collection of products. Although you could loop over all products and attach them one by one using the AttachObjectGraph method, this would have a performance penalty as an automatic preload query would be issued for each item of your collection.

Therefore, I also provided an AttachObjectGraphs method, taking a collection of root entities as the first argument. Using this method, only one single preload query is executed, which would preload all of the products to be attached.

context.AttachObjectGraphs(
    products,
    p => p.Supplier
);

The method returns an array of attached root instances.

Not Updating Path Ends

The call to AttachObjectGraph, as we saw it above, has the following issue:

context.AttachObjectGraph(
    invoice,
    p => p.Customer,
    p => p.Lines.First().Product
);

When attaching an invoice, it will keep the link with its customer, with its invoice lines, and will also keep the link between the lines and their products. This is meant to be.

However, as a 'side effect', any changes done on the customer entity or on the product entities will be applied, and eventually saved as well. Every object within the scope of the object graph will potentially be updated. This could be a serious security thread, and to my knowledge, is an issue also known to the EntityBag solution.

In the case of a 'SaveInvoice' service operation, we want to save the invoice, but not the products. We allow the user to change the price on an invoice line, but we don't want to allow the user to change the price on our product entity, on our products catalogue!

Basically, we need a way to indicate whether changes on the entities at the ends of the paths of the object graph are allowed or not.

To allow this differentiation, I introduced an extension method on entities (IEntityWithKey), which is called "WithoutUpdate()", and only serves as a marker within the object graph path expressions. The method is not to be invoked (and would fail if invoked), but is used by the parser of the expression path arguments to mark the end of the path as updatable or not.

context.AttachObjectGraph(
    invoice,
    p => p.Customer,
    p => p.Lines.First().Product.WithoutUpdate()
);

By extending the path to the products with the WithoutUpdate() method, the invoice lines will be linked to their products, but any changes done on the product entities will not be reflected in the attached invoice (and hence not saved to the database).

Deleting Removed Entities

When calling the SaveInvoice operation with an updated invoice, that invoice will only contain its actual invoice lines. The AttachObjectGraph method is smart enough to detect whether invoice lines have been removed, and will remove those lines from the Lines collection on the attached invoice entity.

However, an invoice line that is removed from its invoice violates the constraint that every invoice line is to have an invoice. When saving the object graph to the database, it will fail.

Ideally, the AttachObjectGraph would detect that it cut a mandatory association, and would automatically perform a delete of the orphan entity.

Unfortunately, I was unable to retrieve, from the Entity Framework, metadata information whether an association is mandatory. So, I've implemented an alternative solution where the owned entity is to be decorated with an AssociationEndBehaviorAttribute, marking the role, for which removed entities are to be deleted, as owned.

Using partial classes, this can perfectly be done without modifying the code generated by the EDM designer, as the attribute is not to be set on the association end property, but on the owner entity type.

To mark the Envoice.Lines role as 'owned' (meaning its values are owned), apply the attribute as follows:

[AssociationEndBehaviorAttribute("Lines", Owned=true)]
partial class Invoice {
}

The AttachObjectGraph method will check for this attribute while navigating the property paths, and will automatically delete each entity which has been removed from the association. Exactly what we needed…

The Code

The sample attached to this article contains all the code of the AttachObjectGraph and AttachObjectGraphs methods, as well as a few extras.

The sample, furthermore, consists of the Entity Framework model of invoicing, a SQL script to reconstruct the (SQL Server) database, and a test project containing Unit Tests demonstrating several scenarios and features of the AttachObjectGraph(s) methods.

Although I talk about the AttachObjectGraph method, its realization is, in reality, a set of methods and classes which would bring us too far to explain in detail here.

The sample contains two additional features which are not discussed in this article, but for which you will find information in the following two posts on my blog:

The Sample Solution

The sample solution consists of the following projects and artifacts:

samplesolution.png

I highlighted the most important items, which I'll shortly describe here:

  • RecreateDatabase.sql: a SQL Server script that will recreate the whole sample database needed to run the sample tests.
  • ObjectContextExtension.cs: this is the place where you'll find the AttachObjectGraph method.
  • Model.edmx (and Model.Designer.cs): the Entity Model generated by the EDM designer.
  • Model.cs: partial class extensions to the Entity Model.
  • SaveInvoiceTests.cs: test methods showing different scenarios calling a SaveInvoice operation.

The TestProject has a dependency to PostSharp. You will need to install PostSharp (http://www.postsharp.org/) to run the solution.

The Test Methods

As to demonstrate several features, and test different scenarios, I didn't provide a 'sample application', but rather a sample set of Unit Tests.

This is the list of Unit Tests provided:

sampletests.png

  • The ListTests class contains 'tests' that write data from the database to the console, and are, in fact, only useful to see what is in the database.
  • The SaveInvoiceTests class contains tests that demonstrate different scenarios to call a SaveInvoice method, as described in this article.
  • The SaveProductTests class contains similar tests to demonstrate the usage of the SaveProduct method.

Let's take a look at one of these test methods:

/// <summary>
/// Test the editing and addition of lines on an invoice to be saved.
/// </summary>
[TestMethod]
[RollingBackTransaction]
public void ExtendInvoiceTest()
{
    Invoice inv = this.GetDetachedInvoice(5);
    InvoiceLine line;
 
    this.ShowInvoice(inv, "Original invoice:");
 
    Assert.AreEqual(1329.98m, inv.TotalPrice);
 
    // Update invoice:
    inv.Customer = this.Customers[3];
    inv.InvoiceDate = inv.InvoiceDate.AddDays(3);
 
    // Update existing line:
    line = inv.Lines.Where(p => p.ID == 8).First();
    line.Product = this.Products[5];
    line.UnitPrice = line.Product.SalePrice;
 
    // Add an extra lines:
    line = new InvoiceLine();
    line.Quantity = 5;
    line.Product = this.Products[6];
    line.UnitPrice = line.Product.SalePrice;
    inv.Lines.Add(line);
 
    // Add another extra line:
    ...
 
    Assert.AreEqual(340.93m, inv.TotalPrice);
 
    // Save invoice:
    inv = this.SaveInvoice(inv);
    this.ShowInvoice(inv, "Saved invoice:");
 
    // Retrieve invoice from store and check total price:
    Assert.AreEqual(340.93m, this.GetDetachedInvoice(5).TotalPrice);
}

The test method is decorated with a TestMethod attribute (of course) and a RollingBackTransaction attribute. The source code of this is provided in the project. The RollingBackTransaction attribute rolls back whatever the test has done on the database, ensuring the database changes are not persisted between tests.

In this test, we first retrieve an invoice, show it (on the console, just for debugging ease), assert its price matches the expected value, then we update the invoice by assigning it a different customer, changing the invoice date, the product, and the unit price of an invoice line, and add two extra invoice lines.

Then, the invoice price is verified to be as expected, before actually saving the invoice. To conclude, the invoice is again retrieved from the database, and its invoice price verified.

Conclusion

Despite the limitations of the Entity Framework to reattach detached entities, the features of .NET 3.5, including Extension Methods, LINQ, Lambda expression parsing, Aspect Oriented Programming, partial classes and methods,... allow us to extend and enhance the existing frameworks seamlessly.

Article History

  • Feb 24, 2009 - v2: Reviewed version; fixed database recreate script; enhanced performance in sample by using preload; explained preload in article.
  • Feb 4, 2009 - v1: Initial version.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Rudi Breedenraedt
Architect Wolters Kluwer Belgium
Belgium Belgium
Member
Rudi is a Software Architect at Wolters Kluwer Belgium.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
SuggestionInheritence supportmemberBlaiseBraye4 Nov '12 - 23:16 
Needing the inheritence support during the attach process, I modified the way the object query is created.
1. I overloaded the GetEntitySetName method in order to get the underlying type of the set with the name.
2. I instantiate the root query with the base type and then call the "OfType" method on this query.
Type baseType;
var setName = GetEntitySetName(context, typeof(T), out baseType);
 
var qType = typeof(ObjectQuery<>).MakeGenericType(baseType);
var q = (ObjectQuery) Activator.CreateInstance(qType, setName, context);
 
//ObjectQuery<T> query = new ObjectQuery<T>(GetEntitySetName(context, typeof(T)), context);

var method = q.GetType().GetMethod("OfType").MakeGenericMethod(typeof (T));
var query = (ObjectQuery<T>) method.Invoke(q, new object[0]);
 
==> thanks to this modification, I am able to give "inclusion paths" which belong to concrete types (e.g. which do not belong to base type).
ex: ATask inherits BaseTask, ATask has many ServicesMappings
ATask task;
domainContext.AttachObjectGraph(task, t=>t.ServiceMappings);
Let's make code sharing our goal...
Blaise Braye

Generalwonderful jobmemberBlaiseBraye4 Nov '12 - 21:55 
wonderful job, big thanks for sharing.
With your strategy, I have been able to establish a behavior "cancel/confirm" very easily:
var taskCopy = domainContext.DetachObjectGraph(task);
            
var vm = new Tasks.TaskAnalyticsRefreshEditorViewModel();
vm.Initialise(taskCopy);
 
var uc = new Tasks.TaskEditor();
uc.DataContext = vm;
 

RadWindow.Confirm(uc, (sender, closedArgs) =>
						  {
							  if (closedArgs.DialogResult == true)
							  {
								  domainContext.AttachObjectGraph(taskCopy);
							  }
						  });
Let's make code sharing our goal...
Blaise Braye

QuestionATTENTION DOWNLOADING DIRECTLY FROM HERE (CODEPROJECT) IS OLD CODE!membergantara13 Jul '12 - 9:00 
I just downloaded the code from here and was riddled why it didnt work at all ...
 

so i just found out the up to date version is to find here:
 

http://ef4tiers.codeplex.com/SourceControl/list/changesets[^]
 
on the right side download...
 
I guess Rudi you can update the files here too and than please delete this comment ^^
AnswerRe: ATTENTION DOWNLOADING DIRECTLY FROM HERE (CODEPROJECT) IS OLD CODE!memberBenjamin Peterson20 Jul '12 - 1:01 
Thanks gantara, I've downloaded the latest. I still need to submit a patch, I think, for the two issues I mentioned. However a third issue - the need to allow multiple AssociationEndBehavior attributes - has been fixed in the codeplex version.
QuestionBrilliant idea!memberBenjamin Peterson13 Jul '12 - 2:07 
Last month I was faced with the realization that EF4 can't re-attach entities. Using it for distributed applications was looking hopeless. That is, until I found this amazing code library. Thanks Rudi! Microsoft really should find a way to pull it into EF5 - it fills a major use-case hole in the design of EF.
 
As a side note, I did end up having to tweak the code a bit to add some features:
1) The ability to attach objects that are marked as internal
2) The ability to disable the automatic preload when reattaching. Large object graphs tend to yield SQL that is horrendously inefficient. I ended up preloading the object graph using different techniques. Perhaps there should be a delegate to inject into the implementation?
 
I'd be happy to contribute to the codeplex project if it's open.
 
Thanks!
-ben
GeneralTHX You saved me :) (STE useless now)membergantara12 Jul '12 - 12:09 
In my opinion this is the greatest method in EF!
 
Am i wrong if i say that this method makes STE's absolutely useless?!
 
Now i can just come back from client with the tree and use this method and everything is fine! Now i have an easy to use way to attach graphs, but can enable lazy loading yay!
 
Thx alot!
GeneralRe: THX You saved me :) (STE useless now)memberRudi Breedenraedt12 Jul '12 - 13:28 
Thanks gantara!
 
Self Tracking Entities (STE) are an application of the Unit of Work design pattern, similar to the now obsolete Entitybag I mention in my article. STE is a different approach than my AttachObjectGraph method, and if you use one approach, the other becomes needless indeed.
 
I guess STE also will have its advocates, but I have seen projects using STE fail due to the complexity in use and the lack of control of the transaction actions.
 
Cheers!
GeneralRe: THX You saved me :) (STE useless now)membergantara13 Jul '12 - 6:16 
Yes indeed,
 
we tried using them too, but the lack of lazyloading and therefore your forced to use tons of includes in your business logic. And if you have that, you have to find a way to tell the BusinessObject what part of the tree you now want do include. I couldnt find a good way for that.
 
I wish you the best, cause still iam using this code in every project ^^
 
Thx again.
Smile | :)
GeneralRe: THX You saved me :) (STE useless now)memberMatthias Muenzner11 Dec '12 - 12:18 
Wanted to say that i found a solution to add Includes if you have a IQueryable(of T)
 
You just have to cast it to ObjectQuery(of T)
 
The wonderfull thing about taht is that now i can call my busineessobjects that return IQueryable and if i need it, i can still add more includes later.
 
And like always: I LOVE YOUR FUNCTION! Wink | ;)
QuestionAwesomememberhodkinsons4 Jul '12 - 20:10 
Unfortunately it seems comments are turned off on your website (that has the latest version). But I wanted to say a big "thank you". This has made my day.
AnswerRe: Awesome - latest version of the codememberRudi Breedenraedt12 Jul '12 - 14:18 
Thanks!
 
Indeed, latest version of the code is available on http://ef4tiers.codeplex.com.
 
> Unfortunately it seems comments are turned off on your website
Yeah, too much spam, need to find out how to set a captcha... But comment is welcome here Smile | :)

QuestionUsing AttachObjectGraph in VB.NETmembergiado19 Jul '11 - 8:38 
Hi,
Im using your code in a ASP.NET/VB.NET application.
I'm getting some problems. I suppose that is caused by some conversion from vb.net to c#.
 
My call to your code is something like
 
GetDBEntities().AttachObjectGraph(toCreate, Function(e) e.edificio.WithoutUpdate, Function(r) r.ruolo, Function(p) p.ruolo.persona.WithoutUpdate)
 
GetDBEntities() returns the context
toCreate is the root object
 
first I have got to change as you see
public static string GetEntitySetName(this ObjectContext context, Type entityType)
{
var container = context.MetadataWorkspace.GetEntityContainer(context.DefaultContainerName, DataSpace.CSpace);
//return (from meta in container.BaseEntitySets
// where meta.ElementType.FullName == entityType.FullName
// select meta.Name).FirstOrDefault();

return (from meta in container.BaseEntitySets
where meta.ElementType.Name == entityType.Name
select meta.Name).FirstOrDefault();
}
 
and now it works for me.
 
But later when there is the call to CollectRelationalMembers I get an expression error because it goes in this condition
 
if (exp.NodeType == ExpressionType.Lambda)
{
// At root, handle body:
CollectRelationalMembers(((LambdaExpression)exp).Body, members);
}
and if I check Body it is
((LambdaExpression)exp).Body = {Convert(e.edificio).WithoutUpdate()}
 
and
members is empty
 
This is the full exception
 
System.InvalidOperationException was caught
Message=Invalid type of expression.
Source=CodeProject.Data
StackTrace:
at CodeProject.Data.Entity.EntityFrameworkHelper.CollectRelationalMembers(Expression exp, IList`1 members) in C:\projects\GEC\CodeProject.Data\Entity\EntityFrameworkHelper.cs:line 49
at CodeProject.Data.Entity.EntityFrameworkHelper.CollectRelationalMembers(Expression exp, IList`1 members) in C:\projects\GEC\CodeProject.Data\Entity\EntityFrameworkHelper.cs:line 35
at CodeProject.Data.Entity.EntityFrameworkHelper.CollectRelationalMembers(Expression exp, IList`1 members) in C:\projects\GEC\CodeProject.Data\Entity\EntityFrameworkHelper.cs:line 16
at CodeProject.Data.Entity.ObjectContextExtension.AttachObjectGraphs[T](ObjectContext context, IEnumerable`1 entities, Expression`1[] paths) in C:\projects\GEC\CodeProject.Data\Entity\ObjectContextExtension.cs:line 100
at CodeProject.Data.Entity.ObjectContextExtension.AttachObjectGraph[T](ObjectContext context, T entity, Expression`1[] paths) in C:\projects\GEC\CodeProject.Data\Entity\ObjectContextExtension.cs:line 29
at GEC.DomandaRepository.Create(Object objectToCreate) in C:\projects\GEC\GEC\Models\DomandaRepository.vb:line 12
InnerException:
 

Could you help me ?
AnswerRe: Using AttachObjectGraph in VB.NETmemberRudi Breedenraedt19 Jul '11 - 11:49 
Hello Giado,
 
I did indeed notice a difference in how the VB.NET compiler translated lambda expressions compared to the C# compiler. Having the InvalidOperationException("Invalid type of exception") means you came in the 'default' case of the switch expression in the CollectRelationalMembers method, as you were aware. What is the node type of the expression of its not one of the foreseen cases ?
 
I'm not that familiar with the VB.NET syntax. Just to check, you say your code is:
GetDBEntities().AttachObjectGraph(toCreate, Function(e) e.edificio.WithoutUpdate, Function(r) r.ruolo, Function(p) p.ruolo.persona.WithoutUpdate)

Shouldn't it be:
GetDBEntities().AttachObjectGraph(toCreate, Function(e) e.edificio.WithoutUpdate(), Function(r) r.ruolo, Function(p) p.ruolo.persona.WithoutUpdate())
 
And finally, have you tried the latest version of the code ? It's available on CodePlex:
http://ef4tiers.codeplex.com/[^]
 
Kind regards
Rudi Breedenraedt
GeneralRe: Using AttachObjectGraph in VB.NETmembergiado20 Jul '11 - 5:40 
Hi Rudi,
I have tested te latest version from codeplex and it works fine.
I see that has been fixed the expression error (there is a 'Convert' case switch that manage VB.NET) and also the there is a fix in the GetEntitySetName.
 
There is still a problem that I have found but I think it is not so easy to solve.
If I have a new object that was a detached copy of a persisted object (but without the EntityKey or other staff like this).
The detached copy and the persisted object just have the same properties value.
If I try to persist the detached object (due to the fact that it doen't have any EntityKey) it doesn't update the persisted object but it insert a new object.
Do you think there is a way in which I can delegate to your code to check if the object (decorating it such a way o something like this) already exist in the db and then update it.
I know better Hibernate (Java version) and it has a method called SaveOrUpdate that first check if the object exist and later decide what to do (I believe that it first try to update and if it fails then insert the object).
This could be very useful becuase when an object travel in different tiers when you finally have to persist it you couldn't know if it is new or modified.
 
Up to now thank your your library, it has solved many problems to me, but of course we could improve.
 
Regards
Giancarlo
GeneralFANTASTIC!memberdiegoss.hhh18 Oct '10 - 9:47 
Man! You saved my life! I've been hating EF until I use it! It was amazing!
Thanks!
GeneralEF v4memberjfioranelli8 Sep '10 - 18:17 
In the article you mentioned that it applies to EF v1 (3.5).
Do you know if EF v4 comes with some new feature that solves this problem?
 
Thanks
GeneralRe: EF v4memberRudi Breedenraedt16 Sep '10 - 12:01 
Hi Jorge,
 
Yes, indeed, EF 4 comes with quite some now features related to the use of Entity Framework in combination with client/server topologies (where object graphs are detached and need to be reattached). For one, the Attach method has been enhanced. But the major new feature in my opinion is the template to work with self-tracking entities which keep track of changes and apply them on attach. Still, not all issues are addressed. There is for instance no concept of a preload query, updating path ends can not be controlled and it influences the (WCF) contracts.
 
So, yes, EF 4 has interesting new features that solves some of the problems. But I think there are still good reasons why you might consider the AttachObjectGraph solution too.
 
I have made the latest version of the code, ported to EF 4, available on CodePlex:
http://ef4tiers.codeplex.com/[^]
 
Kind regards
Rudi
GeneralRe: EF v4memberJorge Fioranelli16 Sep '10 - 13:11 
Thanks Rudi.
 
I was developing a similar solution when I realized you have already developed it! Nice!
 

Kind Regards,
 
Jorge
GeneralRe: EF v4memberjaimebula12 Jan '11 - 14:54 
I checked the codeplex project for V4. But didn´t find a download.
 
Did you post it anywhere else?
 
Best Regards,
 
Jaime
GeneralRe: EF v4memberRudi Breedenraedt13 Jan '11 - 11:10 
Hi Jaime,
 
Indeed, there are no binaries download. You are supposed to download the source code. To do this, go to the "Source Code" tab or use the following link:
http://ef4tiers.codeplex.com/SourceControl/list/changesets[^]
 
On the right of your screen you should find a 'Latest Version' box with a download link.
 
Kind regards
Rudi Breedenraedt
GeneralRe: EF v4memberjaimebula13 Jan '11 - 14:49 
Hi,
 
Found it and compiled it,
 
But i'm getting a warning
 
Warning 1 'System.Data.Objects.ObjectContext.ApplyPropertyChanges(string, object)' is obsolete: 'Use ApplyCurrentValues instead' C:\Users\Jaime\Desktop\ef4tiers-49246\CodeProject.Data\Entity\ObjectContextExtension.cs 132 6 CodeProject.Data
 
Would you consider that updating that line of code is safe?
 
object attachedEntity = context.GetObjectByKey(entityKey);
if (applyPropertyChanges)
context.ApplyPropertyChanges(entityKey.EntitySetName, entity);
return attachedEntity;
 
to
 
object attachedEntity = context.GetObjectByKey(entityKey);
if (applyPropertyChanges)
context.ApplyCurrentValues(entityKey.EntitySetName, entity);
return attachedEntity;
 
Best Regards.
 
Jaime
GeneralRe: EF v4memberRudi Breedenraedt14 Jan '11 - 0:39 
Hi Jaime,
 
Yes, indeed, ApplyPropertyChanges was merely renamed into ApplyCurrentValues. Both methods behave the exact same, so it's safe to use ApplyCurrentValues instead. I'll change that in the CodePlex code as well.
 
Kind regards
 
Rudi Breedenraedt
QuestionHow to handle properties that does NOT exist in the entity metadata.memberJohan Klijn30 May '10 - 19:44 
First of all great article.
 
I have a question. For some of my entity classes I created some partial classes with properties. The XXX uses the ApplyPropertyChanges to update the entity objects retrieved from the store with the values of the Detached object. ApplyPropertyChanges only sets properties that exist in the entity metadata for the type. So, properties that are added in a partial class are not included in the ApplyPropertyChanges operation.
 
Do you have any recommendation how to handle this?
AnswerRe: How to handle properties that does NOT exist in the entity metadata.memberRudi Breedenraedt16 Sep '10 - 11:36 
Hallo Johan,
 
Sorry for the late reply.
 
I don't immediately see an answer to your question that does not impact on the implementation of the AttachObjectGraph method, and hence my preference would go to the least invasive solution, one that would minimize dependency between the AttachObjectGraph method and your specific requirement. The one idea that comes to me is to add events on the AttachObjectGraph 'method' (well, not on the method itself of course, events have to be declared on class level). Every time the AttachObjectGraph method calls ApplyPropertyChanges, it would also raise the event and passing to it the source and target objects. Your event handler would then be able to handle the rest.
 
The event handler could then be kept generic by relying on an interface for the applying of the remaining properties, as in:
 
  AttachHandlers.OnUpdate += new ObjectUpdateHandler(this.UpdateMyPartialProperties);
and
 
  void UpdateMyPartialProperties(object source, ObjectUpdateEventArgs e) {
    var extendedPartial = e.TargetObject as IExtendedPartial;
    if (extendedPartial != null)
       extendedPartial.ApplyCustomPropertyChanges(e.SourceObject);
  }
 
The AttachHanders, ObjectUpdateHandler and IExtendedPartial are types for you to create. This code is just to illustrate what you could do.
 
Groeten,
Rudi
GeneralInheritancememberGarth_S14 Oct '09 - 13:32 
Hi, Great Work!
 
Anyone figured out how to get inherited objects to save?
GeneralRe: Inheritancememberveljkoz15 Oct '09 - 3:07 
There's a new version on his blog[^](his CodeProject account seems to be out of service)
It seems to now include inheritance. Not sure yet, I'm just about to try Smile | :)
GeneralRe: InheritancememberGarth_S15 Oct '09 - 11:47 
It works great. Thanks for your quick feedback. I have spent days trying to figure it out.
 
Cheers.
GeneralRe: InheritancememberGarth_S15 Oct '09 - 17:41 
New problem: Saving inherited objects that don’t already exist in the database works fine. But if I retrieve an object from the database and then add something to a navigational property (on the derived type) I get an exception saying that the navigation property can’t be found on the base type. The exception is coming from ObjectContextExtension.AttachObjectGraphs on the line query.Execute(MergeOption.AppendOnly).ToArray(). Any ideas on a fix for this.
 
Example:
 
MyDerivedClass : MyBaseClass
 
MyDerivedClass has a collection of Comment.
 
If I create a new MyDerivedClass and add a Comment it will save fine:
 
Var derived = new MyDerivedClass()
derived.Comments.Add(new Comment())
Save()
 
But if I query the database to find an existing record and add a comment using:
 
Var dervied = (from c in context.MyBaseClassSet
.OfType()
.Include(“Comments”)
Where ####
Select c).First()
derived.Comments.Add(new Comment())
Save()
 
I get “A specified Include path is not valid. The EntityType ' MyBaseClass' does not declare a navigation property with the name ' Comments '.”
 
Any ideas?
 
Note: the code is just free typed so ignore any syntax or spelling errors.
 
Cheers.
GeneralRe: Inheritance [modified]memberveljkoz16 Oct '09 - 6:55 
The problem is in the "Include" and inheritance - simply you can't use it.
 
This is because the Comments property doesn't exist on the base entity (on which you are calling the Include), and you can't use Include on inherited entity because it doesn't have it's own EntitySet.
 
This really is frustrating, and I can only hope they fixed it in 4.0.
In the meantime, you can fetch like:
 
var tmp = (from c in context.MyBaseClassSet
where ________ && c is DerivedClass
select new {c, (c as DerivedClass).Comments ).FirstOrDefault();
tmp.Comments.Add(new Comment())
 
Entity framework will automatically fill in the Comments property of the "c" because they're both in the select list of the same query (it recognizes if entities in projection list are somehow related and connects them for you).
I haven't tested this, so do reply if it works or not...
Hope it helps
 
--Edit:
As for the AttachObjectGraph - you have to preload all entities manually if EntityKey==null or temporary before the attaching of graph, and comment that part out in Rudi's method.
 
modified on Monday, October 19, 2009 10:05 AM

GeneralRe: InheritancememberJohan Vervloet19 Dec '09 - 11:40 
I fixed it like using this code:
 
// Construct query:
ObjectQuery<T> query = new ObjectQuery<T>(GetEntitySetName(context, typeof(T)), context).OfType<T>();
 
Instead of
 
// Construct query:
ObjectQuery<T> query = (ObjectQuery<T>)context.PublicGetProperty(GetEntitySetName(context, typeof(T)));
 
(
or
 
// Construct query:
ObjectQuery<T> query = new ObjectQuery<T>(GetEntitySetName(context, typeof(T)), context)
 
if you applied the previous fix.
)
GeneralThis is fantasticmemberSeth Dingwell11 Sep '09 - 8:07 
Microsoft should pay you for doing what they should have done in the first place. Thanks for making this public.
GeneralChanging Entity Associationsmembertboe15 Aug '09 - 1:48 
Great job. Just one question:
You are mantioning the following potential scenarios (quote):
 
- creating a new invoice
- editing an invoice by changing properties (i.e., InvoiceDate, StateCode, Comments, …)
- editing an invoice by adding lines
- editing an invoice by editing lines (i.e., setting a different Quantity or Product)
- editing an invoice by removing lines
- changing the supplier of a product
 
After that you are saying:
"All but the last of these scenarios will be supported by one single implementation of a SaveInvoice (server) operation..."
 
However, this is exactly the scenario I am currently stuck with. Is there any way of handling changed entity associations as well? I think it is a quite common case that e.g. the product of a supplier changed on the client. Unfortunately the ApplyPropertyChanged() method in EF 1 does not cover this.
 
Any kind of help would be very much appreciated.
GeneralRe: Changing Entity AssociationsmemberRudi Breedenraedt16 Aug '09 - 4:30 
Hallo tboe. Thanks!
What I meant is that all 5 first scenarios are variations of saving an invoice and can be handled with a single SaveInvoice operation. They include handling changed entity associations, of course, as otherwise you wouldn't really be saving an object graph.
The last scenario, changing the supplier of a product, can perfectly be covered by the following implementation:
 
void SaveProduct(Product product)
{
    using (var context = new SampleInvoiceContext())
    {
        context.AttachObjectGraph(
            product,
            p => p.Supplier.WithoutUpdate()
        );
 
        context.SaveChanges();
    }
}
 
By providing the path p.Supplier you ensure that the association with the supplier is saved as well. The operation will also save changes to the name or the price of the product. However, the WithoutUpdate() call ensures the SaveProduct operation is protected against changes on the Supplier instance itself (so you can't change the name of the supplier with this operation). If you don't want this protection, just leave the call to WithoutUpdate() away.
 
Kind regards
Rudi Breedenraedt
GeneralHaving poblem when I using include (It is ExtensionMethod of Class ObjectContext). it throw InvlidOperationException .memberbest192729 Jul '09 - 18:12 
Entity TN_HUMAN has Navigation Property is TN_CARS.
Entity TN_CAR has Navigation Prperty is Human.
 
TN_HUMAN Related with TN_CAR by TH_HUMAN.ID = TN_CAR.HUMAN_ID.
TN_HUMAN 1--*TN_CAR
 
Code
var qs = From et In en.TN_HUMAN.Include(p => p.TN_CARS) Where et.NAME = "Entity" Select et
 
Original Code:
Dim qs = From et In en.TN_HUMAN.Include(Function(p As TN_HUMAN) p.TN_CARS) Where et.NAME = "Entity" Select et
 
Ps. I Programming with VB.Net
I use <a href="http://www.developerfusion.com/tools/convert/vb-to-csharp/">http://www.developerfusion.com/tools/convert/vb-to-csharp/</a>[<a href="http://www.developerfusion.com/tools/convert/vb-to-csharp/" target="_blank" title="New Window">^</a>] convert C# To VB.Net
GeneralRe: Having poblem when I using include (It is ExtensionMethod of Class ObjectContext). it throw InvlidOperationException .memberRudi Breedenraedt21 Aug '09 - 5:35 
Hi,
First of all, sorry for this late replay.
 
Indeed, there has been an issue reported when using the AttachObjectGraph method from VB.NET.
 
It appears lambda expressions are translated slightly differently when coded in VB.NET compared to C#...
 
The issue is solved, but for now only available on my blog:
http://www.codetuning.net/blog/post/Entity-Framework-reattaching-entity-graphs-(3).aspx[^]
 
Download the code attached to the blog article, it's the same as the code you can download on this article, except it has a few fixes including a fix for VB.NET.
 
Would you still have issues, could you then try not translating the AttachObjectGraph code to VB.NET, but just compile it in C# to an assembly which you can then use from your VB.NET code ? If it then works, we know the issue is related to either the translation, or the VB.NET compiler.
 
The next update of the code on this page will include this fix.
 
Kind regards
 
Rudi Breedenraedt
GeneralGreat job, thanks!!memberArnold E. Schrijver28 Jul '09 - 6:36 
Thanks, you saved me a lot of work (and having to wait for EF 2.0 Laugh | :laugh: ), Rudi.
Excellent article!
 
Arnold Schrijver

GeneralRe: Great job, thanks!!memberRudi Breedenraedt21 Aug '09 - 5:37 
Thanks for your feedback, and happy you enjoyed Smile | :)
GeneralCode correction that enables handling of collections with new entities related to entities that already exists in dbmemberehlers7520 Jul '09 - 23:50 
The original code is not able to update an existing entity that have a related collection with new entities in it.
 
My case is the following:
 
I have a Filter with a collection of FilterAnalysisNames.
When updating a filter with the following command it failed:
 
dtContext.AttachObjectGraph(
                              filter,
                              p => p.FilterAnalysisName
                              );
 
<pre>The following correction to AddOrAttachInstance fixed it for me:
 
            /// &lt;summary&gt;
            /// Adds or attaches the entity to the context. If the entity has an EntityKey,
            /// the entity is attached, otherwise a clone of it is added.
            /// &lt;/summary&gt;
            /// &lt;returns&gt;The attached entity.&lt;/returns&gt;
            public static object AddOrAttachInstance(this ObjectContext context, object entity, bool applyPropertyChanges)
            {
                  EntityKey entityKey = ((IEntityWithKey)entity).EntityKey;
                  if (entityKey == null || entityKey.EntityKeyValues == null)   //ehlers75: added "|| entityKey.EntityKeyValues == null" to handle newly added related entities on existing entities that is being updated. They have an entitiy key but no entity key values.
                  {
                        object attachedEntity = GetShallowEntityClone(entity);
                        context.AddObject(context.GetEntitySetName(entity.GetType()), attachedEntity);
                        if (entityKey == null)   //ehlers75: added to handle newly added related entities on existing entities that is being updated.
                        {
                              ((IEntityWithKey)entity).EntityKey = ((IEntityWithKey)attachedEntity).EntityKey;
                        }
 
                        return attachedEntity;
                  }
                  else
                  {
                        object attachedEntity = context.GetObjectByKey(entityKey);
                        if (applyPropertyChanges)
                              context.ApplyPropertyChanges(entityKey.EntitySetName, entity);
                        return attachedEntity;
                  }
            }
 
</pre>
QuestionNice, but how get worked over wcf ? [modified]memberbartosi10 Jul '09 - 12:37 
Hello Rudi!
I like this article very much, but because I'm a quite new to this environment, is not clear, how should it use in an n-tier environment.
Could you, or anybody else explain (with a little code), how should this AttachObjectGraph approach use over a wcf serice ?
-- please help!
Thank you, Istvan Bartos.
 
modified on Saturday, July 11, 2009 6:30 PM

QuestionRemove Paths ?memberMohamed Meligy7 Jun '09 - 20:36 
Hey,
How about if I have an object graph that is modified in different user controls, each modifying different paths in the object graph? I would then love to be able to save the entire diff in object graph with one call without having to modify this call based on what data (paths) each control will change.
 
Simply speaking, is is possible to call this method and let it save the entire object graph ?
GeneralYou may have just saved Entity Framework for me.membermbujak6 May '09 - 22:55 
I am just now learning Entity Framework and WCF. I have a model for my DAL and when I try to bring an entity or entity collection with child (owned) entities I across the wire through a WCF service, I get all kinds of exceptions. If I bring across a single object or collection without the related items, it works fine. Does this solve that problem?
 
Example:
 
This code works......
public static GetCompanies(string category)
{
   using(InformEntities ents = new InformEntities())
   {
      var q = from c in ents.CompanyCategories.Include("Companies")
             where c.Name == category
             select c;
     
      if(q != null && q.Count() > 0)
          return q.First().Companies.ToList();
    }
    return null;
}
This code does not work:
public static GetCompaniesWithEmployees(string category)
{
   using(InformEntities ents = new InformEntities())
   {
      var q = from c in ents.CompanyCategories
                  .Include("Companies")
                  .Include("Employees")
             where c.Name == category
             select c;
     
      if(q != null && q.Count() > 0)
          return q.First().Companies.ToList();
    }
    return null;
}
 
At first I thought it was a size limit so I changed the config file but this did not work. Can this be done in EF and if not, does your solution solve tis problem?
 
Anyway, great article, if this does what I think it does, you may have just saved the Entity Framework for me...... I just started the project and was really looking forward to using it....
 
Mike B
QuestionIssue while using CompiledQuery [modified]memberArun Venkatesh25 Apr '09 - 2:27 
Excellent work Rudi. Thanks very much.
 
While trying your solution I encountered an issue using "Include" extension in a CompiledQuery. The query works just fine without the CompiledQuery option. Am I missing something?
 
var selected = CompiledQuery.Compile((MyEntities myEntities) =>
                        from   q
                        in     myEntities.Query
                               .Include(p => p.QueryLogs)
                        where  q.QueryID == queryID
                        select q);
 
I get this error
 
"System.NotSupportedException: LINQ to Entities does not recognize the method 'System.Data.Objects.ObjectQuery`1[BusinessEntities.Query] Include[Query](System.Data.Objects.ObjectQuery`1[BusinessEntities.Query], System.Linq.Expressions.Expression`1[System.Func`2[BusinessEntities.Query,System.Object]])' method, and this method cannot be translated into a store expression.."
 
modified on Tuesday, May 5, 2009 9:53 AM

GeneralFind owned relations without custom attributesmemberIvan Poloziuk20 Apr '09 - 20:58 
Great article!
 
Owned relations can be easily identified by the multiplicity of source end: if it's RelationshipMultiplicity.One - then it's owned and should be deleted as well.
 
The following is what I tweaked at the method NavigatePropertySet:
 

instead of:

// Delete removed items if association is owned:
if (AssociationEndBehaviorAttribute.GetAttribute(property.PropertyInfo).Owned)
{
foreach (var removedItem in removedItems)
context.DeleteObject(removedItem);
}

 
added:

// Remove related object if multiplicity of the source end is RelationshipMultiplicity.One
var associationSet = relatedEnd.RelationshipSet as AssociationSet;
if (associationSet != null &&
associationSet.AssociationSetEnds[relatedEnd.SourceRoleName].CorrespondingAssociationEndMember.
RelationshipMultiplicity == RelationshipMultiplicity.One)
{
foreach (object removedItem in removedItems)
context.DeleteObject(removedItem);
}

 
It works for me, probably need to test it a bit to be sure it work all times.
 

 
Regards,
Ivan Poloziuk
GeneralRe: Find owned relations without custom attributesmemberric3ca23 Apr '09 - 5:03 
Great tip Ivan.
I had this problem and you tip work for me too.
 
Ricardo
GeneralQuery related to AttachObjectGraph methodmemberashwanigl20 Apr '09 - 1:07 
This is a great article. Could you please provide the code for the following method as well. Instead of taking Expression as input parameter would it be possible if it takes string array of related objects.
 
context.AttachObjectGraph(
invoice,
"Customer",
"Lines.Product"
);
 

Thanks
GeneralRe: Query related to AttachObjectGraph methodmemberRudi Breedenraedt23 Apr '09 - 13:47 
Thanks ashwanigl.
 
Could you explain me why you would want this option ?
 
As I see it, this option would have two problems:
1. it's not compile safe and should therefore be strongly discouraged
2. it would not support extensions as the ".WithoutUpdate()" method
 
But that's my opinion. I'm curious about your point of view.
 
Kind regards
 
Rudi Breedenraedt
GeneralCreates a new record always even the object is updatingmemberAjay Bal4 Apr '09 - 1:34 
Absolutely a clean and workable concept. Full marks.
But I am having two problems
1. Object even while updating, is still creating another entry in database.
I am using attribute
<optimisticconcurrency("useddate"), GetType(LocalDateTimeConcurrencyResolver)&gt;
 
Here UsedDate property is same as LastModified.
 
2. Still not able to find equivalent of
p => p.Supplier.WithoutUpdate();
in VB.net 9.0 with sp1 as the method WithoutUpdate is not supposed to be invoked.
 
If you feel it to be feasible to reply to Ist problem, I can provide more details. Or maybe I am missing somthing ?
 
A big thanks once again !
GeneralRe: Creates a new record always even the object is updatingmemberRudi Breedenraedt21 Aug '09 - 5:45 
Hi Ajay,
Sorry for this very late reply...
 
Do you still have your 1st problem ? If so, do you have this problem with the provided unittests as well ? Or can you try a case using the sample ? The sample uses the same mechanism and a LastChanged property, so you either would have the issue there too, or should be able to compare the sample's code with your code and explain the problem. I hope...
 
For your second issue, this is how you should use the WithoutUpdate method from within VB.NET:
context.AttachObjectGraph(product, Function(p) p.Supplier.WithoutUpdate())
 
However, to use the AttachObjectGraph method from VB, you will need the latest version, which is currently not yet available on this page, but can be found on my blog:
http://www.codetuning.net/blog/post/Entity-Framework-reattaching-entity-graphs-(3).aspx[^]
 
This version fixes an issue with VB.NET, and also contains a VB.NET unittest project as sample.
 
Kind regards
Rudi Breedenraedt
GeneralProblem with SQL Server timestampmemberjbernsen19731 Apr '09 - 4:13 
Nice work but I have a little problem when using SQL server timestamps for optimistic concurrency.
 
I keep getting the OptimisticConcurrencyException when updating an entity. It seems like the ObjectStateManager always marks the bytearray for the timestamp as modified after ApplyPropertyChanges. Does anyone have the same problem or a solution ?
 
Thanx,
 
Jeroen
GeneralRe: Problem with SQL Server timestampmemberAleksejMi2 Dec '10 - 1:38 
Actually I have the same problem. On my datetime field if I want to update it the event WhenSavingChanges would fire and next code line would return true
 
if (attr.HasPropertyChanged(this.context, entity))
throw new OptimisticConcurrencyException(String.Format("Concurrency property {0}.{1} contains invalid update.", entity.GetType(), attr.PropertyName));

 

on the other hand if I don't update my field with newer version of datetime it would remain the same even after few updates.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130516.1 | Last Updated 10 Mar 2009
Article Copyright 2009 by Rudi Breedenraedt
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid