0

ドメインとして EF4 プロジェクトを使用している MVC3 プロジェクトがあります。Domain は、T4 を使用して POCO オブジェクトを構築する Model first プロジェクトです。ドメインにはいくつかの ComplexTypes があり、context.CreateObject() によって返されるプロキシを使用する限り、すべてがうまく機能します。

MVC3 アクションが呼び出されると、モデル バインダーは、ドメインに適用される変更を含む非プロキシ オブジェクトを渡します。

ビューが後でナビゲーションプロパティにアクセスできるように、「プロキシされた」オリジナルを操作したいので、まっすぐにAttachToを使用してもうまくいきません。

最初にコンテキストから「元の」プロキシ オブジェクトを取得し、次にモデル バインダーによって提供される POCO に含まれる変更で更新する必要があります。

私が読んだことと、私の調査によると、次のようなものを使用してこれを達成できるはずです。

public static T GetUpdatedProxy<T>(this ObjectContext context, string entitySetName, T entity)
    where T : class
{
    object original; // db original POCO, proxy wrapped.
    var entityKey = context.CreateEntityKey(entitySetName, entity);

    //Load DB object
    context.GetObjectByKey(entityKey, out original)
    //Apply changes from binder supplied POCO object.
    context.ApplyCurrentValues<T>(entitySetName, entity); //<= error here
    return (T) original;
}

私の問題はこのエラーです:

[InvalidOperationException: The entity of type 'System.Data.Entity.DynamicProxies.Value_E954C24C522BA1D4124F434A57391656EFA4DD7CEFFD3A5CE35FC1532CD1B10A' references the same complex object of type 'Domain.DateRange' more than once. Complex objects cannot be referenced multiple times by the same entity.]
   System.Data.Objects.EntityEntry.CheckForDuplicateComplexObjects(Object complexObject) +418
   System.Data.Objects.EntityEntry.DetectChangesInProperties(Boolean detectOnlyComplexProperties) +211
   System.Data.Objects.Internal.EntityWithChangeTrackerStrategy.UpdateCurrentValueRecord(Object value, EntityEntry entry) +93
   System.Data.Objects.Internal.EntityWrapper`1.UpdateCurrentValueRecord(Object value, EntityEntry entry) +17
   System.Data.Objects.EntityEntry.ApplyCurrentValuesInternal(IEntityWrapper wrappedCurrentEntity) +107
   System.Data.Objects.ObjectContext.ApplyCurrentValues(String entitySetName, TEntity currentEntity) +365
  • 非プロキシ オブジェクトの複合オブジェクトとプロキシされたオブジェクトの複合オブジェクトは同じではありません。
  • エンティティには 1 つの複合オブジェクトしかないため、同じ ComplexType の 2 つのプロパティを複数回設定することはできません。
  • 複合オブジェクト自体には実際には値が設定されていないため、2 つの null 許容フィールドは実際にはまだ null のままです。
  • AttachTo メソッドを使用し、オブジェクトの状態を変更済みに設定すると、保存は機能しますが、後でオブジェクトを使用してビューを返すことはできません。これは、ナビゲーション プロパティが null であるためです。

何かご意見は?助けてくれてありがとう。

4

1 に答える 1

0

私はついに回避策を見つけました。私は完全にcontext.ApplyCurrentValues()をPOCOからプロキシに機能させることができませんでした。

私が思いついた解決策は、IOC CreateObject()メソッドから新しいプロキシを作成し、リフレクションを使用してPOCOのプロパティを反復処理してコピーし、プロキシでAttachTo()を呼び出すことでした。

public static T GetUpdatedProxy<T>(this ObjectContext context, string entitySetName, T entity)
    where T : class
{
    var proxy = context.CreateObject<T>();

    //Copy ComplexObjects and values over.
    foreach(var property in typeof(T).GetProperties().Where(p => p.CanWrite && p.CanRead))
        if(typeof(IComplexObject).IsAssignableFrom(property.PropertyType))
            proxy.SetValueOf(property, (entity.GetValueOf(property) as IComplexObject).Clone()); //<== Clone the ComplexType
        else if(typeof(System.ValueType).IsAssignableFrom(property.PropertyType) || typeof(System.String).IsAssignableFrom(property.PropertyType))
            proxy.SetValueOf(property, entity.GetValueOf(property));

    context.AttachTo(entitySetName, proxy);
    context.ObjectStateManager.ChangeObjectState(entity, EntityState.Modified);
    entity = (T) proxy;
}

プロパティを反復して、コンテキストからプリロードされたプロキシにコピーしようとしました。TryGetObjectByKey(entityKey、out getObject)ですが、コンテキストを保存しようとすると、複雑なオブジェクトがnull(そうではなかった)であるという別のエラーが発生します。 。

クローン可能なインターフェイスとその実装をt4テンプレートのComplexTypesに追加しました。

public interface IComplexObject : ICloneable {}
...
object ICloneable.Clone(){ return this.Clone(); }
public DateRange Clone(){ return (DateRange) this.MemberwiseClone(); }

SetValueOfとGetValueOfは、読みやすさのために使用する単純な拡張メソッドです。

public static object GetValueOf(this object item, PropertyInfo property)
{
    return property.GetValue(item, null);
}

public static object GetValueOf(this object item, string property)
{
    return GetValueOf(item, item.GetType().GetProperty(property));
}

public static void SetValueOf(this object item, PropertyInfo property, object value)
{
    property.SetValue(item, value, null);
}

public static void SetValueOf(this object item, string property, object value)
{
    SetValueOf(item, item.GetType().GetProperty(property), value);
}
于 2011-10-08T16:13:10.213 に答える