Применение текущих значений из POCO к DynamicProxy дает ошибку на сложных объектах - PullRequest
0 голосов
/ 06 октября 2011

У меня есть проект MVC3, который использует проект EF4 в качестве своего домена. Домен является первым проектом Model, который использует T4 для создания объектов POCO. В Домене есть несколько 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
  • Сложный объект на непрокси-объекте и один на прокси-объект не то же самое.
  • У сущности есть только один сложный объект, поэтому его нельзя установить несколько раз, скажем, два свойства одного и того же ComplexType.
  • Самому сложному объекту на самом деле не были установлены какие-либо значения, поэтому два пустых поля на самом деле все еще равны нулю.
  • Если я использую метод AttachTo, а затем устанавливаю состояние объекта для изменения сохраненных работ, но позже я не могу использовать объект для возврата представления, потому что свойства навигации равны нулю.

Есть мысли? Я ценю помощь.

1 Ответ

0 голосов
/ 08 октября 2011

Я наконец-то нашел обходной путь.Я был абсолютно не в состоянии получить 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;
}

Я пытался выполнить итерацию и скопировать свойства в предварительно загруженный прокси из context.TryGetObjectByKey (entityKey, out getObject), но это могло бы дать мне другую ошибку о том, что сложный объект является нулевым (чего не было)t) когда я попытался сохранить контекст.

я добавил интерфейс с возможностью клонирования и его реализации для ComplexTypes в шаблоне t4:

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

SetValueOf и GetValueOf - простые методы расширения Iиспользовать для удобства чтения:

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);
}
...