私は Entityframework を使用したシステムに取り組んでおり、もう 12 か月以上になりますが、昨日までプロジェクトは順調に進んでいました。しかし、昨日、なぜ発生するのか分からない奇妙なエラーが発生しました。以前と何も変わっていませんが、問題のエンティティをロードして子エンティティにアクセスしようとすると、次のエラーが発生します。
The entity wrapper stored in the proxy does not reference the same proxy
これが実際に何を意味し、何が原因なのかを誰か解明できますか?
コードを見せてもあまり役に立ちません。
コードの簡略版を以下に示します。
var quote = new QuoteHelper().GetById(orderId);
var updatedQuotes = new Provider().GetExportQuotes(quote.DeparturePoint.Id,quote.DestinationPoint);
DeparturePoint および DestinationPoint にアクセスするとエラーが発生しますが、Quote は正しく読み込まれ、すべてのプロパティが読み込まれます。
エンティティ Quote は次のようになります。
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; }
}
ベストアンサー1
これは、エンティティに ICloneable を実装し、MemberwiseClone を使用してそれを複製しようとしたときにも発生しました。自分でインスタンス化したエンティティを使用していたときはうまく機能しました。ただし、これを使用して EF を使用してロードされたエンティティを複製すると、DbSet (または他のさまざまな部分) に追加しようとするたびにこのエラーが発生しました。
少し調べてみると、EF で読み込まれたエンティティを複製すると、プロキシ クラスも複製されることがわかりました。プロキシ クラスが持ち運ぶものの 1 つは、特定のエンティティのラッパーへの参照です。浅いコピーではラッパーへの参照のみがコピーされるため、突然、同じラッパー インスタンスを持つ 2 つのエンティティができます。
この時点で、EF は、エンティティに対して別のプロキシ クラスを作成または借用したと判断し、それが悪意のある目的であると想定してブロックします。
編集
この問題を回避するために作成したスニペットを以下に示します。これは EF プロパティのみをコピーするのに十分な機能を果たしますが、完璧ではありません。プライベート フィールドもコピーする必要がある場合は変更する必要がありますが、考え方は理解できます。
/// <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;
}