/// <summary> /// Instantiates the class using default components /// </summary> /// <param name="dbContext">Context in which to perform the merge operation</param> /// <param name="modelsNamespace">Namespace in which all context entities are defined (all models must be within /// the same namespace. If model type is in a different namespace, an exception will be thrown when instantiating /// the type. This is, hopefully, a temporary workaround, until I find a good solution for this)</param> /// <param name="modelAssemblyName">Name of assembly which contains all context enties. Again, just like with the /// namespace parameter, this is a temporary workaround</param> public DefaultEntityChangesMerger(DbContext dbContext, string modelsNamespace, string modelAssemblyName) { DbContext = dbContext; reflector = new DbContextReflector(DbContext, modelsNamespace, modelAssemblyName); scalarUpdater = new ScalarPropertyUpdater(DbContext, reflector); entityComparer = new EntityComparerByNonForeignKeys(); collectionMerger = new CollectionMerger(entityComparer); navUpdater = new NavigationPropertyUpdater(DbContext, scalarUpdater, reflector); }
public TEntity UpdateEntity <TEntity>(TEntity model, IRecursiveEntityUpdater updater) where TEntity : class { // Update scalar properties TEntity updatedModel = UpdateEntity <TEntity>(model); UpdateAllNavigationProperties(updatedModel, model, updater, updatedModel == model); return(updatedModel); }
/*public void UpdateCollection(Expression<Func<TModel, IList<TCollectionEntry>>> property, object sourceModel) * { * MemberExpression mex = (MemberExpression)property.Body; * UpdateCollection((PropertyInfo)mex.Member, sourceModel); * }*/ public void UpdateCollection <TCollectionEntry>(IDbContextReflector reflector, NavigationPropertyInfo property, object sourceModel, bool modelIsNew, IRecursiveEntityUpdater entityUpdater) where TCollectionEntry : class { Reflector = reflector; Property = property; EntityUpdater = entityUpdater; if (modelIsNew) { AddCollection((IList <TCollectionEntry>)property.PropertyInfo.GetValue(sourceModel)); } else { UpdateCollection((IList <TCollectionEntry>)property.PropertyInfo.GetValue(Model), (IList <TCollectionEntry>)property.PropertyInfo.GetValue(sourceModel)); } }
protected override void UpdateAllNavigationProperties <TEntity>(TEntity updatedModel, TEntity model, IRecursiveEntityUpdater entityUpdater, bool isNew) { EntityNavigationPropertyInfo[] collectionProperties = Reflector.GetCollectionNavigationProperties(typeof(TEntity)); // make it work like <TModel> var collectionUpdater = new ReflectingGenericCollectionPropertyUpdater <TEntity>(new CollectionPropertyUpdater <TEntity>(DbContext, updatedModel, CollectionMerger)); foreach (var property in collectionProperties) { collectionUpdater.UpdateCollectionProperty(Reflector, property, model, isNew, entityUpdater); } }
protected abstract void UpdateAllNavigationProperties <TEntity>(TEntity updatedModel, TEntity model, IRecursiveEntityUpdater entityUpdater, bool isNew) where TEntity : class;
protected override void UpdateAllNavigationProperties <TEntity>(TEntity updatedModel, TEntity model, IRecursiveEntityUpdater entityUpdater, bool modelIsNew) { EntityNavigationPropertyInfo[] navigationProperties = Reflector.GetDependentNavigationProperties(typeof(TEntity)); var modelUpdater = new ReflectingGenericEntityUpdater <TEntity>(); foreach (var property in navigationProperties) { modelUpdater.UpdateProperty(property, model, entityUpdater); /* TODO: cover scenarios where navigation property has a corresponding foreign key (Id) property. * Make sure updates work well in those cases because sometimes navigation property might not be loaded (== null) * but the foreign key property is non-default. In such cases, navigation property of the target model should * not be set to null. */ } }
public void UpdateProperty(EntityNavigationPropertyInfo property, TModel newModel, IRecursiveEntityUpdater entityUpdater) { GenericMethodInvoker.InvokeGenericMethod(typeof(IRecursiveEntityUpdater), nameof(IRecursiveEntityUpdater.UpdateEntity), new Type[] { property.PropertyInfo.PropertyType }, GenericMethodInvoker.DefaultPublicInstanceBindingFlags, new object[] { property.PropertyInfo.GetValue(newModel), entityUpdater }, entityUpdater); }