/// <inheritdoc /> public virtual async Task DeleteAsync(TId id, CancellationToken cancellationToken) { _traceWriter.LogMethodStart(new { id }); using var collector = new PlaceholderResourceCollector(_resourceFactory, _dbContext); TResource resource = collector.CreateForId <TResource, TId>(id); foreach (RelationshipAttribute relationship in _resourceGraph.GetRelationships <TResource>()) { // Loads the data of the relationship, if in EF Core it is configured in such a way that loading the related // entities into memory is required for successfully executing the selected deletion behavior. if (RequiresLoadOfRelationshipForDeletion(relationship)) { NavigationEntry navigation = GetNavigationEntry(resource, relationship); await navigation.LoadAsync(cancellationToken); } } _dbContext.Remove(resource); await SaveChangesAsync(cancellationToken); }
/// <inheritdoc /> public virtual async Task RemoveFromToManyRelationshipAsync(TResource primaryResource, ISet <IIdentifiable> secondaryResourceIds, CancellationToken cancellationToken) { _traceWriter.LogMethodStart(new { primaryResource, secondaryResourceIds }); ArgumentGuard.NotNull(secondaryResourceIds, nameof(secondaryResourceIds)); var relationship = (HasManyAttribute)_targetedFields.Relationships.Single(); object rightValue = relationship.GetValue(primaryResource); HashSet <IIdentifiable> rightResourceIds = _collectionConverter.ExtractResources(rightValue).ToHashSet(IdentifiableComparer.Instance); rightResourceIds.ExceptWith(secondaryResourceIds); AssertIsNotClearingRequiredRelationship(relationship, primaryResource, rightResourceIds); using var collector = new PlaceholderResourceCollector(_resourceFactory, _dbContext); await UpdateRelationshipAsync(relationship, primaryResource, rightResourceIds, collector, cancellationToken); await SaveChangesAsync(cancellationToken); }
/// <inheritdoc /> public virtual async Task CreateAsync(TResource resourceFromRequest, TResource resourceForDatabase, CancellationToken cancellationToken) { _traceWriter.LogMethodStart(new { resourceFromRequest, resourceForDatabase }); ArgumentGuard.NotNull(resourceFromRequest, nameof(resourceFromRequest)); ArgumentGuard.NotNull(resourceForDatabase, nameof(resourceForDatabase)); using var collector = new PlaceholderResourceCollector(_resourceFactory, _dbContext); foreach (var relationship in _targetedFields.Relationships) { var rightResources = relationship.GetValue(resourceFromRequest); await UpdateRelationshipAsync(relationship, resourceForDatabase, rightResources, collector, cancellationToken); } foreach (var attribute in _targetedFields.Attributes) { attribute.SetValue(resourceForDatabase, attribute.GetValue(resourceFromRequest)); } var dbSet = _dbContext.Set <TResource>(); await dbSet.AddAsync(resourceForDatabase, cancellationToken); await SaveChangesAsync(cancellationToken); }
/// <inheritdoc /> public virtual async Task UpdateAsync(TResource resourceFromRequest, TResource resourceFromDatabase, CancellationToken cancellationToken) { _traceWriter.LogMethodStart(new { resourceFromRequest, resourceFromDatabase }); ArgumentGuard.NotNull(resourceFromRequest, nameof(resourceFromRequest)); ArgumentGuard.NotNull(resourceFromDatabase, nameof(resourceFromDatabase)); using var collector = new PlaceholderResourceCollector(_resourceFactory, _dbContext); foreach (RelationshipAttribute relationship in _targetedFields.Relationships) { object rightResources = relationship.GetValue(resourceFromRequest); AssertIsNotClearingRequiredRelationship(relationship, resourceFromDatabase, rightResources); await UpdateRelationshipAsync(relationship, resourceFromDatabase, rightResources, collector, cancellationToken); } foreach (AttrAttribute attribute in _targetedFields.Attributes) { attribute.SetValue(resourceFromDatabase, attribute.GetValue(resourceFromRequest)); } await SaveChangesAsync(cancellationToken); }
/// <inheritdoc /> public virtual async Task DeleteAsync(TId id, CancellationToken cancellationToken) { _traceWriter.LogMethodStart(new { id }); // This enables OnWritingAsync() to fetch the resource, which adds it to the change tracker. // If so, we'll reuse the tracked resource instead of a placeholder resource. var emptyResource = _resourceFactory.CreateInstance <TResource>(); emptyResource.Id = id; await _resourceDefinitionAccessor.OnWritingAsync(emptyResource, OperationKind.DeleteResource, cancellationToken); using var collector = new PlaceholderResourceCollector(_resourceFactory, _dbContext); TResource resource = collector.CreateForId <TResource, TId>(id); foreach (RelationshipAttribute relationship in _resourceGraph.GetRelationships <TResource>()) { // Loads the data of the relationship, if in EF Core it is configured in such a way that loading the related // entities into memory is required for successfully executing the selected deletion behavior. if (RequiresLoadOfRelationshipForDeletion(relationship)) { NavigationEntry navigation = GetNavigationEntry(resource, relationship); await navigation.LoadAsync(cancellationToken); } } _dbContext.Remove(resource); await SaveChangesAsync(cancellationToken); await _resourceDefinitionAccessor.OnWriteSucceededAsync(resource, OperationKind.DeleteResource, cancellationToken); }
/// <inheritdoc /> public virtual async Task AddToToManyRelationshipAsync(TId primaryId, ISet <IIdentifiable> secondaryResourceIds, CancellationToken cancellationToken) { _traceWriter.LogMethodStart(new { primaryId, secondaryResourceIds }); ArgumentGuard.NotNull(secondaryResourceIds, nameof(secondaryResourceIds)); var relationship = (HasManyAttribute)_targetedFields.Relationships.Single(); await _resourceDefinitionAccessor.OnAddToRelationshipAsync <TResource, TId>(primaryId, relationship, secondaryResourceIds, cancellationToken); if (secondaryResourceIds.Any()) { using var collector = new PlaceholderResourceCollector(_resourceFactory, _dbContext); TResource primaryResource = collector.CreateForId <TResource, TId>(primaryId); await UpdateRelationshipAsync(relationship, primaryResource, secondaryResourceIds, collector, cancellationToken); await _resourceDefinitionAccessor.OnWritingAsync(primaryResource, OperationKind.AddToRelationship, cancellationToken); await SaveChangesAsync(cancellationToken); await _resourceDefinitionAccessor.OnWriteSucceededAsync(primaryResource, OperationKind.AddToRelationship, cancellationToken); } }
/// <inheritdoc /> public virtual async Task SetRelationshipAsync(TResource primaryResource, object secondaryResourceIds, CancellationToken cancellationToken) { _traceWriter.LogMethodStart(new { primaryResource, secondaryResourceIds }); var relationship = _targetedFields.Relationships.Single(); AssertIsNotClearingRequiredRelationship(relationship, primaryResource, secondaryResourceIds); using var collector = new PlaceholderResourceCollector(_resourceFactory, _dbContext); await UpdateRelationshipAsync(relationship, primaryResource, secondaryResourceIds, collector, cancellationToken); await SaveChangesAsync(cancellationToken); }
protected async Task UpdateRelationshipAsync(RelationshipAttribute relationship, TResource leftResource, object valueToAssign, PlaceholderResourceCollector collector, CancellationToken cancellationToken) { object trackedValueToAssign = EnsureRelationshipValueToAssignIsTracked(valueToAssign, relationship.Property.PropertyType, collector); if (RequireLoadOfInverseRelationship(relationship, trackedValueToAssign)) { EntityEntry entityEntry = _dbContext.Entry(trackedValueToAssign); string inversePropertyName = relationship.InverseNavigationProperty.Name; await entityEntry.Reference(inversePropertyName).LoadAsync(cancellationToken); } relationship.SetValue(leftResource, trackedValueToAssign); }
private object EnsureRelationshipValueToAssignIsTracked(object rightValue, Type relationshipPropertyType, PlaceholderResourceCollector collector) { if (rightValue == null) { return(null); } var rightResources = TypeHelper.ExtractResources(rightValue); var rightResourcesTracked = rightResources.Select(collector.CaptureExisting).ToArray(); return(rightValue is IEnumerable ? (object)TypeHelper.CopyToTypedCollection(rightResourcesTracked, relationshipPropertyType) : rightResourcesTracked.Single()); }
/// <inheritdoc /> public virtual async Task AddToToManyRelationshipAsync(TId primaryId, ISet <IIdentifiable> secondaryResourceIds, CancellationToken cancellationToken) { _traceWriter.LogMethodStart(new { primaryId, secondaryResourceIds }); if (secondaryResourceIds == null) { throw new ArgumentNullException(nameof(secondaryResourceIds)); } var relationship = _targetedFields.Relationships.Single(); if (secondaryResourceIds.Any()) { using var collector = new PlaceholderResourceCollector(_resourceFactory, _dbContext); var primaryResource = collector.CreateForId <TResource, TId>(primaryId); await UpdateRelationshipAsync(relationship, primaryResource, secondaryResourceIds, collector, cancellationToken); await SaveChangesAsync(cancellationToken); } }
/// <inheritdoc /> public virtual async Task CreateAsync(TResource resource, CancellationToken cancellationToken) { _traceWriter.LogMethodStart(new { resource }); if (resource == null) { throw new ArgumentNullException(nameof(resource)); } using var collector = new PlaceholderResourceCollector(_resourceFactory, _dbContext); foreach (var relationship in _targetedFields.Relationships) { var rightValue = relationship.GetValue(resource); await UpdateRelationshipAsync(relationship, resource, rightValue, collector, cancellationToken); } var dbSet = _dbContext.Set <TResource>(); dbSet.Add(resource); await SaveChangesAsync(cancellationToken); }
/// <inheritdoc /> public virtual async Task CreateAsync(TResource resourceFromRequest, TResource resourceForDatabase, CancellationToken cancellationToken) { _traceWriter.LogMethodStart(new { resourceFromRequest, resourceForDatabase }); ArgumentGuard.NotNull(resourceFromRequest, nameof(resourceFromRequest)); ArgumentGuard.NotNull(resourceForDatabase, nameof(resourceForDatabase)); using var collector = new PlaceholderResourceCollector(_resourceFactory, _dbContext); foreach (RelationshipAttribute relationship in _targetedFields.Relationships) { object rightResources = relationship.GetValue(resourceFromRequest); object rightResourcesEdited = await VisitSetRelationshipAsync(resourceForDatabase, relationship, rightResources, OperationKind.CreateResource, cancellationToken); await UpdateRelationshipAsync(relationship, resourceForDatabase, rightResourcesEdited, collector, cancellationToken); } foreach (AttrAttribute attribute in _targetedFields.Attributes) { attribute.SetValue(resourceForDatabase, attribute.GetValue(resourceFromRequest)); } await _resourceDefinitionAccessor.OnWritingAsync(resourceForDatabase, OperationKind.CreateResource, cancellationToken); DbSet <TResource> dbSet = _dbContext.Set <TResource>(); await dbSet.AddAsync(resourceForDatabase, cancellationToken); await SaveChangesAsync(cancellationToken); await _resourceDefinitionAccessor.OnWriteSucceededAsync(resourceForDatabase, OperationKind.CreateResource, cancellationToken); }
/// <inheritdoc /> public virtual async Task SetRelationshipAsync(TResource primaryResource, object secondaryResourceIds, CancellationToken cancellationToken) { _traceWriter.LogMethodStart(new { primaryResource, secondaryResourceIds }); RelationshipAttribute relationship = _targetedFields.Relationships.Single(); object secondaryResourceIdsEdited = await VisitSetRelationshipAsync(primaryResource, relationship, secondaryResourceIds, OperationKind.SetRelationship, cancellationToken); AssertIsNotClearingRequiredRelationship(relationship, primaryResource, secondaryResourceIdsEdited); using var collector = new PlaceholderResourceCollector(_resourceFactory, _dbContext); await UpdateRelationshipAsync(relationship, primaryResource, secondaryResourceIdsEdited, collector, cancellationToken); await _resourceDefinitionAccessor.OnWritingAsync(primaryResource, OperationKind.SetRelationship, cancellationToken); await SaveChangesAsync(cancellationToken); await _resourceDefinitionAccessor.OnWriteSucceededAsync(primaryResource, OperationKind.SetRelationship, cancellationToken); }
private object EnsureRelationshipValueToAssignIsTracked(object rightValue, Type relationshipPropertyType, PlaceholderResourceCollector collector) { if (rightValue == null) { return null; } ICollection<IIdentifiable> rightResources = _collectionConverter.ExtractResources(rightValue); IIdentifiable[] rightResourcesTracked = rightResources.Select(collector.CaptureExisting).ToArray(); return rightValue is IEnumerable ? (object)_collectionConverter.CopyToTypedCollection(rightResourcesTracked, relationshipPropertyType) : rightResourcesTracked.Single(); }