24

I am working on a system using Entityframework and have been for over 12monts now, and the project has been going well, up until yesterday, where I have now got a strange error which I have no idea why it occurs. I am doing nothing different to what I have done before, but once I load the entity in question and try to access any child entities I get the following error:

The entity wrapper stored in the proxy does not reference the same proxy

Can anyone shed any light on what this actually means and what would cause this?

Showing my code doesnt really help.

Here is a simplified version of the code:

var quote = new QuoteHelper().GetById(orderId);
var updatedQuotes = new Provider().GetExportQuotes(quote.DeparturePoint.Id,quote.DestinationPoint);

The error occurs when accessing DeparturePoint and DestinationPoint but Quote loads correctly, and all properties are loaded.

The entity Quote looks a little like this:

public class Quote : BaseQuote, ICloneable
{
     public Guid DeparturePointId { get; set; }
     public virtual LocationPoint DeparturePoint{ get; set; }

     public Guid DestinationPointId { get; set; }
     public virtual LocationPoint DestinationPoint{ get; set; }
}
JamesStuddart
  • 2,581
  • 3
  • 27
  • 45

3 Answers3

48

This happened to me too when I tried to implement ICloneable on my entity and cloned it using MemberwiseClone. Worked great when I was using entities that I instantiated myself. However, when I used this to clone an entity that had been loaded using EF, I got this error whenever I tried to add it to a DbSet (or in various other parts).

After some digging, I found that when you clone an EF-loaded entity, you're cloning the proxy class as well. One of the things a proxy class carries around is a reference to the wrapper fo the given entity. Because a shallow copy only copies a reference to the wrapper, you suddenly have two entities that have the same wrapper instance.

At this point, EF thinks you've created or borrowed a different proxy class for your entity which it assumes is for purposes of mischief and blocks you.

Edit

Here's a snippet that I created to work around this problem. Note that this will do a fair job of copying just the EF properties, but it's not perfect. Note that you'll need to modify it if you have private fields that must be copied as well, but you get the idea.

    /// <summary>
    /// Makes a shallow copy of an entity object. This works much like a MemberwiseClone
    /// but directly instantiates a new object and copies only properties that work with
    /// EF and don't have the NotMappedAttribute.
    /// </summary>
    /// <typeparam name="TEntity">The entity type.</typeparam>
    /// <param name="source">The source entity.</param>
    public static TEntity ShallowCopyEntity<TEntity>(TEntity source) where TEntity : class, new()
    {

        // Get properties from EF that are read/write and not marked witht he NotMappedAttribute
        var sourceProperties = typeof(TEntity)
                                .GetProperties()
                                .Where(p => p.CanRead && p.CanWrite &&
                                            p.GetCustomAttributes(typeof(System.ComponentModel.DataAnnotations.NotMappedAttribute), true).Length == 0);
        var newObj = new TEntity();

        foreach (var property in sourceProperties)
        {

            // Copy value
            property.SetValue(newObj, property.GetValue(source, null), null);

        }

        return newObj;

    }
N Jones
  • 1,004
  • 11
  • 18
  • 1
    Thanks,I had a horrible clone method and memberwise seemed like the magic I needed seems like its not. Thanks. – JamesStuddart Sep 12 '12 at 13:33
  • MemberwiseClone often is the magic you need, but EF does some unique things. By the way, if you find this solution isn't sufficient, I've also heard of people using [AutoMapper](http://automapper.org/) for a cheap cloning mechanism. It wasn't intended for this, but that doesn't mean it isn't a perfectly good solution. – N Jones Sep 12 '12 at 17:28
  • Thanks, I have made a botch work around for the issue, but when I get the time to come back to it I will implement one of the solutions you have given. Thanks for your insight, it seems there isnt much out there on this issue and I hope this helps other people out too. – JamesStuddart Sep 13 '12 at 09:37
  • 1
    for use NotMappedAttribute property ,go to https://stackoverflow.com/questions/12194267/updated-to-ef5-now-notmapped-annotation-doesnt-work – MJ Vakili Dec 12 '17 at 07:30
  • 5
    Shouldn't "System.ComponentModel.DataAnnotations.NotMappedAttribute" be "System.ComponentModel.DataAnnotations.Schema.NotMappedAttribute"? – Elton Apr 28 '20 at 16:34
  • If "Collection was modified; enumeration operation may not execute." error pops, check Lorena Pita's answer. – buraky Apr 03 '23 at 16:05
2

I solved it this way.

using (var ctx = new MyContext())
      {
         ctx.Configuration.ProxyCreationEnabled = false;

         return ctx.Deferrals.AsNoTracking().Where(r => 
         r.DeferralID.Equals(deferralID)).FirstOrDefault();
      }
Lorena Pita
  • 1,366
  • 1
  • 17
  • 20
  • I used N Jones' solution and it gave exception with "Collection was modified; enumeration operation may not execute.". This answer solved that problem. – buraky Apr 03 '23 at 16:04
1

Above solution may occur such as error "Conflicting changes to the role x of the relationship y have been detected". I achieve that error with using this method;

 public virtual TEntity DetachEntity(TEntity entityToDetach)
    {
        if (entityToDetach != null)
            context.Entry(entityToDetach).State = EntityState.Detached;
        context.SaveChanges();
        return entityToDetach;
    }

i hope it'll work for you too.