private static void RemoveDenormalizedInstances( IStateManager stateManager, INavigation navigation, object entity, object instance) { InternalEntityEntry internalEntityEntry = stateManager.TryGetEntry(entity); internalEntityEntry.EnsureRelationshipSnapshot(); INavigation inverse = navigation.FindInverse(); IKey primaryKey = inverse.DeclaringEntityType.FindPrimaryKey(); IProperty primaryKeyProperty = primaryKey.Properties.Single(); object keyValue = primaryKeyProperty.GetGetter().GetClrValue(instance); IClrCollectionAccessor collectionAccessor = navigation.GetCollectionAccessor(); ICollection list = (ICollection)collectionAccessor.GetOrCreate(entity); IList <object> toRemove = list .OfType <object>() .Where(item => (Equals( keyValue, primaryKeyProperty.GetGetter().GetClrValue(item)) && !ReferenceEquals(instance, item))) .ToList(); foreach (object item in toRemove) { collectionAccessor.Remove(entity, item); internalEntityEntry.RemoveFromCollectionSnapshot(navigation, item); } }
private static TCollection PopulateCollection <TEntity, TCollection>( IClrCollectionAccessor accessor, IEnumerable <TEntity> entities) { // TODO: throw a better exception for non ICollection navigations var collection = (ICollection <TEntity>)accessor.Create(); foreach (var entity in entities) { collection.Add(entity); } return((TCollection)collection); }
private void SetReferenceOrAddToCollection( InternalEntityEntry entry, INavigation navigation, IClrCollectionAccessor collectionAccessor, object value) { if (collectionAccessor != null) { AddToCollection(entry, navigation, collectionAccessor, value); } else { SetNavigation(entry, navigation, value); } }
private void RemoveFromCollection( InternalEntityEntry entry, INavigation navigation, IClrCollectionAccessor collectionAccessor, object value) { _changeDetector.Suspend(); try { collectionAccessor.Remove(entry.Entity, value); } finally { _changeDetector.Resume(); } entry.RemoveFromCollectionSnapshot(navigation, value); }
private static TCollection MaterializeCollection <TElement, TCollection>( QueryContext queryContext, IEnumerable <ValueBuffer> innerValueBuffers, Func <QueryContext, ValueBuffer, TElement> innerShaper, IClrCollectionAccessor clrCollectionAccessor) where TCollection : class, ICollection <TElement> { var collection = (TCollection)(clrCollectionAccessor?.Create() ?? new List <TElement>()); foreach (var valueBuffer in innerValueBuffers) { var element = innerShaper(queryContext, valueBuffer); collection.Add(element); } return(collection); }
private static void InitializeCollectionInclude <TEntity, TIncludingEntity>( int collectionId, QueryContext queryContext, DbDataReader dbDataReader, ResultCoordinator resultCoordinator, TEntity entity, Func <QueryContext, DbDataReader, object[]> outerIdentifier, INavigation navigation, IClrCollectionAccessor clrCollectionAccessor, bool trackingQuery) where TIncludingEntity : TEntity { object collection = null; if (entity is TIncludingEntity) { // Include case if (trackingQuery) { queryContext.StateManager.TryGetEntry(entity).SetIsLoaded(navigation); } else { SetIsLoadedNoTracking(entity, navigation); } collection = clrCollectionAccessor.GetOrCreate(entity); } var outerKey = outerIdentifier(queryContext, dbDataReader); var collectionMaterializationContext = new CollectionMaterializationContext(entity, collection, outerKey); if (resultCoordinator.Collections.Count == collectionId) { resultCoordinator.Collections.Add(collectionMaterializationContext); } else { resultCoordinator.Collections[collectionId] = collectionMaterializationContext; } }
private static TCollection InitializeCollection <TElement, TCollection>( int collectionId, QueryContext queryContext, DbDataReader dbDataReader, ResultCoordinator resultCoordinator, Func <QueryContext, DbDataReader, object[]> parentIdentifier, Func <QueryContext, DbDataReader, object[]> outerIdentifier, IClrCollectionAccessor clrCollectionAccessor) where TCollection : class, IEnumerable <TElement> { var collection = clrCollectionAccessor?.Create() ?? new List <TElement>(); var parentKey = parentIdentifier(queryContext, dbDataReader); var outerKey = outerIdentifier(queryContext, dbDataReader); var collectionMaterializationContext = new CollectionMaterializationContext(null, collection, parentKey, outerKey); resultCoordinator.SetCollectionMaterializationContext(collectionId, collectionMaterializationContext); return((TCollection)collection); }
/// <inheritdoc /> public override void IncludeCollection <TEntity, TRelated, TElement>( int includeId, INavigation navigation, INavigation inverseNavigation, IEntityType targetEntityType, IClrCollectionAccessor clrCollectionAccessor, IClrPropertySetter inverseClrPropertySetter, bool tracking, TEntity entity, Func <IEnumerable <TRelated> > relatedEntitiesFactory, Func <TEntity, TRelated, bool> joinPredicate) { Check.NotNull(clrCollectionAccessor, nameof(clrCollectionAccessor)); Check.NotNull(inverseNavigation, nameof(inverseNavigation)); Check.NotNull(inverseClrPropertySetter, nameof(inverseClrPropertySetter)); ICollection <TRelated> collection = (ICollection <TRelated>)clrCollectionAccessor .GetOrCreate(entity); IClrPropertyGetter primaryKeyPropertyGetter = inverseNavigation .DeclaringEntityType .FindPrimaryKey() .Properties .Single() .GetGetter(); IEnumerable <(TRelated, TRelated)> relatedEntities = relatedEntitiesFactory() .Join(collection, related => primaryKeyPropertyGetter.GetClrValue(related), related => primaryKeyPropertyGetter.GetClrValue(related), (related, original) => (related, original)) .ToList(); foreach ((TRelated related, TRelated original) in relatedEntities) { collection.Remove(original); collection.Add(related); inverseClrPropertySetter.SetClrValue(related, entity); } }
private void AddToCollection( InternalEntityEntry entry, INavigation navigation, IClrCollectionAccessor collectionAccessor, object value) { if (navigation != null) { _changeDetector.Suspend(); try { if (collectionAccessor.Add(entry.Entity, value)) { entry.AddToCollectionSnapshot(navigation, value); } } finally { _changeDetector.Resume(); } } }
private static void InitializeIncludeCollection <TParent, TNavigationEntity>( int collectionId, QueryContext queryContext, DbDataReader dbDataReader, ResultCoordinator resultCoordinator, TParent entity, Func <QueryContext, DbDataReader, object[]> parentIdentifier, Func <QueryContext, DbDataReader, object[]> outerIdentifier, INavigation navigation, IClrCollectionAccessor clrCollectionAccessor, bool trackingQuery) where TNavigationEntity : TParent { object collection = null; if (entity is TNavigationEntity) { if (trackingQuery) { queryContext.SetNavigationIsLoaded(entity, navigation); } else { SetIsLoadedNoTracking(entity, navigation); } collection = clrCollectionAccessor.GetOrCreate(entity, forMaterialization: true); } var parentKey = parentIdentifier(queryContext, dbDataReader); var outerKey = outerIdentifier(queryContext, dbDataReader); var collectionMaterializationContext = new CollectionMaterializationContext(entity, collection, parentKey, outerKey); resultCoordinator.SetCollectionMaterializationContext(collectionId, collectionMaterializationContext); }
public object CreateSecurityObject(IModel model, ISecurityObjectRepository securityObjectRepository) { Type targetType = RealObject.GetType(); SecurityObject = Activator.CreateInstance(RealObject.GetType()); IEntityType entityType = model.FindEntityType(targetType); IEnumerable <PropertyInfo> propertiesInfo = targetType.GetRuntimeProperties(); IEnumerable <INavigation> navigations = entityType.GetNavigations(); foreach (PropertyInfo propertyInfo in propertiesInfo) { object defaultValue = propertyInfo.GetValue(SecurityObject); defaultValueDictionary[propertyInfo.Name] = defaultValue; if (this.IsPropertyBlocked(propertyInfo.Name)) { if (navigations.Any(p => p.Name == propertyInfo.Name)) { INavigation navigation = navigations.First(p => p.Name == propertyInfo.Name); if (navigation.IsCollection()) { if (propertyInfo.SetMethod != null) { propertyInfo.SetValue(SecurityObject, null); } } } continue; } if (navigations.Any(p => p.Name == propertyInfo.Name)) { INavigation navigation = navigations.First(p => p.Name == propertyInfo.Name); if (navigation.IsCollection()) { IClrCollectionAccessor collectionAccessor = navigation.GetCollectionAccessor(); IEnumerable objectRealListProperty = (IEnumerable)propertyInfo.GetValue(RealObject); IEnumerable objectSecurityListProperty = (IEnumerable)propertyInfo.GetValue(SecurityObject); List <object> denyObject; BlockedObjectsInListProperty.TryGetValue(propertyInfo.Name, out denyObject); if (objectRealListProperty != null) { foreach (object objInList in objectRealListProperty) { if (denyObject != null && denyObject.Contains(objInList)) { continue; } object objectToAdd; SecurityObjectBuilder metadata = securityObjectRepository.GetObjectMetaData(objInList); if (metadata != null) { if (metadata.SecurityObject != null) { objectToAdd = metadata.SecurityObject; } else { objectToAdd = metadata.CreateSecurityObject(model, securityObjectRepository); } } else { throw new Exception(); } collectionAccessor.Add(SecurityObject, objectToAdd); } } } else { object realValue = propertyInfo.GetValue(RealObject); SecurityObjectBuilder metadata = securityObjectRepository.GetObjectMetaData(realValue); if (metadata != null && realValue != null) { if (metadata.SecurityObject == null) { metadata.SecurityObject = metadata.CreateSecurityObject(model, securityObjectRepository); } if (propertyInfo.SetMethod != null) { propertyInfo.SetValue(SecurityObject, metadata.SecurityObject); } } else { if (propertyInfo.SetMethod != null) { propertyInfo.SetValue(SecurityObject, realValue); } } } } else { if (propertyInfo.SetMethod != null) { object realValue = propertyInfo.GetValue(RealObject); propertyInfo.SetValue(SecurityObject, realValue); } } } foreach (PropertyInfo propertyInfo in propertiesInfo) { object originalValue = propertyInfo.GetValue(SecurityObject); originalValueSecurityObjectDictionary.Add(propertyInfo.Name, originalValue); } if (SecurityObject is ISecurityEntity) { ISecurityEntity securityEntity = (ISecurityEntity)SecurityObject; List <string> blockedMembers = new List <string>(); blockedMembers.AddRange(BlockedProperties); blockedMembers.AddRange(BlockedNavigationProperties); securityEntity.BlockedMembers = blockedMembers; } return(SecurityObject); }
private void SetReferenceOrAddToCollection( InternalEntityEntry entry, INavigation navigation, IClrCollectionAccessor collectionAccessor, object value) { if (collectionAccessor != null) { AddToCollection(entry, navigation, collectionAccessor, value); } else { SetNavigation(entry, navigation, value); } }
private void InitialFixup(StateEntry entry, EntityState oldState) { var entityType = entry.EntityType; foreach (var navigation in entityType.Navigations) { var navigationValue = entry[navigation]; if (navigationValue != null) { if (navigation.IsCollection()) { NavigationCollectionChangedAction( entry, navigation, ((IEnumerable)navigationValue).Cast <object>().ToList(), Enumerable.Empty <object>()); } else { NavigationReferenceChangedAction( entry, navigation, null, navigationValue); } } } var stateEntries = entry.StateManager.StateEntries.ToList(); // TODO: Perf on this state manager query foreach (var navigation in _model.Service.EntityTypes .SelectMany(e => e.Navigations) .Where(n => n.GetTargetType() == entityType)) { IClrCollectionAccessor collectionAccessor = null; if (navigation.IsCollection()) { collectionAccessor = _collectionAccessorSource.GetAccessor(navigation); } var navigationEntityType = navigation.EntityType; foreach (var relatedEntry in stateEntries) { if (relatedEntry.EntityType != navigationEntityType || relatedEntry == entry) { continue; } if (collectionAccessor != null) { if (collectionAccessor.Contains(relatedEntry.Entity, entry.Entity)) { NavigationCollectionChangedAction( relatedEntry, navigation, new[] { entry.Entity }, Enumerable.Empty <object>()); } } else { var navigationValue = relatedEntry[navigation]; if (navigationValue != null) { if (ReferenceEquals(navigationValue, entry.Entity)) { NavigationReferenceChangedAction( relatedEntry, navigation, null, navigationValue); } } } } } foreach (var foreignKey in entityType.ForeignKeys) { var principalEntry = entry.StateManager.GetPrincipal(entry.RelationshipsSnapshot, foreignKey); if (principalEntry != null) { DoFixup(foreignKey, principalEntry, new[] { entry }); } } foreach (var foreignKey in _model.Service.GetReferencingForeignKeys(entityType)) { var dependents = entry.StateManager.GetDependents(entry, foreignKey).ToArray(); if (dependents.Length > 0) { DoFixup(foreignKey, entry, dependents); } } }
/// <inheritdoc /> public override void IncludeCollection <TEntity, TRelated, TElement>( int includeId, INavigation navigation, INavigation inverseNavigation, IEntityType targetEntityType, IClrCollectionAccessor clrCollectionAccessor, IClrPropertySetter inverseClrPropertySetter, bool tracking, TEntity entity, Func <IEnumerable <TRelated> > relatedEntitiesFactory, Func <TEntity, TRelated, bool> joinPredicate) { Check.NotNull(clrCollectionAccessor, nameof(clrCollectionAccessor)); Check.NotNull(inverseNavigation, nameof(inverseNavigation)); Check.NotNull(inverseClrPropertySetter, nameof(inverseClrPropertySetter)); ICollection <TRelated> collection = (ICollection <TRelated>)clrCollectionAccessor .GetOrCreate(entity); IClrPropertyGetter primaryKeyPropertyGetter = navigation .GetTargetType() .FindPrimaryKey() .Properties .Single() .GetGetter(); IDictionary <object, TRelated> replacementMap = relatedEntitiesFactory() .ToDictionary( related => primaryKeyPropertyGetter.GetClrValue(related)); IEnumerable <object> newCollectionItems = collection .Select(original => replacementMap.TryGetValue( primaryKeyPropertyGetter.GetClrValue(original), out TRelated related) ? related : original) .Cast <object>() .ToList(); collection.Clear(); foreach (TRelated item in newCollectionItems) { inverseClrPropertySetter.SetClrValue(item, entity); if (tracking) { InternalEntityEntry originalEntry = _stateManager.TryGetEntry(item); if (originalEntry != null) { _stateManager.StopTracking(originalEntry); } base.StartTracking( LoadEntity( item, targetEntityType, entity, inverseNavigation), targetEntityType); } } }
private void InitialFixup(InternalEntityEntry entry) { var entityType = entry.EntityType; // If the new state is unchanged (such as from a query or Attach) then we are going // to assume that the FK value is the source of truth and not attempt to ascertain // relationships from navigation properties if (entry.EntityState != EntityState.Unchanged) { foreach (var navigation in entityType.GetNavigations()) { var navigationValue = entry[navigation]; if (navigationValue != null) { if (navigation.IsCollection()) { NavigationCollectionChangedAction( entry, navigation, ((IEnumerable)navigationValue).Cast <object>().ToList(), Enumerable.Empty <object>()); } else { NavigationReferenceChangedAction( entry, navigation, null, navigationValue); } } } var entries = entry.StateManager.Entries.ToList(); // TODO: Perf on this state manager query foreach (var navigation in _model.EntityTypes .SelectMany(e => e.GetNavigations()) .Where(n => n.GetTargetType().IsAssignableFrom(entityType))) { IClrCollectionAccessor collectionAccessor = null; if (navigation.IsCollection()) { collectionAccessor = _collectionAccessorSource.GetAccessor(navigation); } var navigationEntityType = navigation.DeclaringEntityType; foreach (var relatedEntry in entries) { if (!navigationEntityType.IsAssignableFrom(relatedEntry.EntityType) || relatedEntry == entry) { continue; } if (collectionAccessor != null) { if (collectionAccessor.Contains(relatedEntry.Entity, entry.Entity)) { NavigationCollectionChangedAction( relatedEntry, navigation, new[] { entry.Entity }, Enumerable.Empty <object>()); } } else { var navigationValue = relatedEntry[navigation]; if (navigationValue != null) { if (ReferenceEquals(navigationValue, entry.Entity)) { NavigationReferenceChangedAction( relatedEntry, navigation, null, navigationValue); } } } } } } foreach (var foreignKey in entityType.GetForeignKeys()) { var principalEntry = entry.StateManager.GetPrincipal(entry.RelationshipsSnapshot, foreignKey); if (principalEntry != null) { DoFixup(foreignKey, principalEntry, new[] { entry }); } } foreach (var foreignKey in _model.FindReferencingForeignKeys(entityType)) { var dependents = entry.StateManager.GetDependents(entry, foreignKey).ToArray(); if (dependents.Length > 0) { DoFixup(foreignKey, entry, dependents); } } }
private void RemoveFromCollection( InternalEntityEntry entry, INavigation navigation, IClrCollectionAccessor collectionAccessor, object value) { _changeDetector.Suspend(); try { collectionAccessor.Remove(entry.Entity, value); } finally { _changeDetector.Resume(); } entry.RemoveFromCollectionSnapshot(navigation, value); }
/// <summary> /// This API supports the Entity Framework Core infrastructure and is not intended to be used /// directly from your code. This API may change or be removed in future releases. /// </summary> public virtual async Task IncludeCollectionAsync( int includeId, INavigation navigation, INavigation inverseNavigation, IEntityType targetEntityType, IClrCollectionAccessor clrCollectionAccessor, IClrPropertySetter inverseClrPropertySetter, bool tracking, object entity, Func <IAsyncEnumerable <object> > relatedEntitiesFactory, CancellationToken cancellationToken) { IDisposable untypedAsyncEnumerator = null; IAsyncEnumerator <object> asyncEnumerator = null; if (includeId == -1 || !_includedCollections.TryGetValue(includeId, out untypedAsyncEnumerator)) { asyncEnumerator = relatedEntitiesFactory().GetEnumerator(); if (!await asyncEnumerator.MoveNext(cancellationToken)) { asyncEnumerator.Dispose(); asyncEnumerator = null; } if (includeId != -1) { _includedCollections.Add(includeId, asyncEnumerator); } } if (asyncEnumerator == null) { if (untypedAsyncEnumerator == null) { clrCollectionAccessor.GetOrCreate(entity); return; } asyncEnumerator = (IAsyncEnumerator <object>)untypedAsyncEnumerator; } var relatedEntities = new List <object>(); // TODO: This should be done at query compile time and not require a VB unless there are shadow props var keyComparer = CreateIncludeKeyComparer(entity, navigation); while (true) { bool shouldInclude; if (_valueBuffers.TryGetValue(asyncEnumerator.Current, out var relatedValueBuffer)) { shouldInclude = keyComparer.ShouldInclude((ValueBuffer)relatedValueBuffer); } else { var entry = _dependencies.StateManager.TryGetEntry(asyncEnumerator.Current); Debug.Assert(entry != null); shouldInclude = keyComparer.ShouldInclude(entry); } if (shouldInclude) { relatedEntities.Add(asyncEnumerator.Current); if (tracking) { StartTracking(asyncEnumerator.Current, targetEntityType); } if (inverseNavigation != null) { Debug.Assert(inverseClrPropertySetter != null); inverseClrPropertySetter.SetClrValue(asyncEnumerator.Current, entity); if (tracking) { var internalEntityEntry = _dependencies.StateManager.TryGetEntry(asyncEnumerator.Current); Debug.Assert(internalEntityEntry != null); internalEntityEntry.SetRelationshipSnapshotValue(inverseNavigation, entity); } } if (!await asyncEnumerator.MoveNext(cancellationToken)) { asyncEnumerator.Dispose(); _includedCollections[includeId] = null; break; } } else { break; } } clrCollectionAccessor.AddRange(entity, relatedEntities); if (tracking) { var internalEntityEntry = _dependencies.StateManager.TryGetEntry(entity); Debug.Assert(internalEntityEntry != null); internalEntityEntry.AddRangeToCollectionSnapshot(navigation, relatedEntities); internalEntityEntry.SetIsLoaded(navigation); } }
public object CreateRealObject(IModel model, ISecurityObjectRepository securityObjectRepository) { Type targetType = SecurityObject.GetType(); RealObject = Activator.CreateInstance(SecurityObject.GetType()); IEntityType entityType = model.FindEntityType(targetType); IEnumerable <PropertyInfo> properiesInfo = targetType.GetRuntimeProperties(); IEnumerable <INavigation> navigations = entityType.GetNavigations(); IReadOnlyList <IProperty> primaryKeyProperties = entityType.FindPrimaryKey().Properties; foreach (PropertyInfo propertyInfo in properiesInfo) { object defaultValue = propertyInfo.GetValue(RealObject); defaultValueDictionary[propertyInfo.Name] = defaultValue; if (navigations.Any(p => p.Name == propertyInfo.Name)) { INavigation navigation = navigations.First(p => p.Name == propertyInfo.Name); if (navigation.IsCollection()) { IClrCollectionAccessor collectionAccessor = navigation.GetCollectionAccessor(); IEnumerable realObjectListPropertyValue = (IEnumerable)propertyInfo.GetValue(RealObject); IEnumerable securityObjectListPropertyValue = (IEnumerable)propertyInfo.GetValue(SecurityObject); if (securityObjectListPropertyValue != null && realObjectListPropertyValue != null) { foreach (object objectInListProperty in securityObjectListPropertyValue) { SecurityObjectBuilder metadata = securityObjectRepository.GetObjectMetaData(objectInListProperty); if (metadata == null) { metadata = new SecurityObjectBuilder(); securityObjectRepository.RegisterBuilder(metadata); metadata.SecurityObject = objectInListProperty; metadata.CreateRealObject(model, securityObjectRepository); } collectionAccessor.Add(RealObject, metadata.RealObject); } } } else { object realValue = propertyInfo.GetValue(SecurityObject); if (!Equals(realValue, null)) { SecurityObjectBuilder metadata = securityObjectRepository.GetObjectMetaData(realValue); if (metadata == null) { metadata = new SecurityObjectBuilder(); securityObjectRepository.RegisterBuilder(metadata); metadata.SecurityObject = realValue; metadata.CreateRealObject(model, securityObjectRepository); } if (propertyInfo.SetMethod != null) { propertyInfo.SetValue(RealObject, metadata.RealObject); } } } } else { bool isGeneratedPrimaryKey = false; foreach (IProperty primaryKeyProperty in primaryKeyProperties) { if ((propertyInfo.Name == primaryKeyProperty.Name) && primaryKeyProperty.RequiresValueGenerator) { isGeneratedPrimaryKey = true; } } if (propertyInfo.SetMethod != null && !isGeneratedPrimaryKey) { object securityValue = propertyInfo.GetValue(SecurityObject); propertyInfo.SetValue(RealObject, securityValue); } } } return(RealObject); }
private void AddToCollection( InternalEntityEntry entry, INavigation navigation, IClrCollectionAccessor collectionAccessor, object value) { if (navigation != null) { _changeDetector.Suspend(); try { if (collectionAccessor.Add(entry.Entity, value)) { entry.AddToCollectionSnapshot(navigation, value); } } finally { _changeDetector.Resume(); } } }