public virtual async Task DeleteAsync(TId id) { _logger.LogTrace($"Entering {nameof(DeleteAsync)}('{id}')."); if (!IsNull(_hookExecutor)) { var entity = _resourceFactory.CreateInstance <TResource>(); entity.Id = id; _hookExecutor.BeforeDelete(AsList(entity), ResourcePipeline.Delete); } var succeeded = await _repository.DeleteAsync(id); if (!succeeded) { string resourceId = TypeHelper.GetResourceStringId <TResource, TId>(id, _resourceFactory); throw new ResourceNotFoundException(resourceId, _currentRequestResource.ResourceName); } if (!IsNull(_hookExecutor)) { var entity = _resourceFactory.CreateInstance <TResource>(); entity.Id = id; _hookExecutor.AfterDelete(AsList(entity), ResourcePipeline.Delete, succeeded); } }
/// <inheritdoc /> public virtual async Task DeleteAsync(TId id) { _traceWriter.LogMethodStart(new { id }); if (_hookExecutor != null) { var resource = _resourceFactory.CreateInstance <TResource>(); resource.Id = id; _hookExecutor.BeforeDelete(AsList(resource), ResourcePipeline.Delete); } var succeeded = await _repository.DeleteAsync(id); if (_hookExecutor != null) { var resource = _resourceFactory.CreateInstance <TResource>(); resource.Id = id; _hookExecutor.AfterDelete(AsList(resource), ResourcePipeline.Delete, succeeded); } if (!succeeded) { AssertPrimaryResourceExists(null); } }
public virtual async Task DeleteAsync(TId id) { _logger.LogTrace($"Entering {nameof(DeleteAsync)}('{id}')."); if (_hookExecutor != null) { var resource = _resourceFactory.CreateInstance <TResource>(); resource.Id = id; _hookExecutor.BeforeDelete(AsList(resource), ResourcePipeline.Delete); } var succeeded = await _repository.DeleteAsync(id); if (_hookExecutor != null) { var resource = _resourceFactory.CreateInstance <TResource>(); resource.Id = id; _hookExecutor.AfterDelete(AsList(resource), ResourcePipeline.Delete, succeeded); } if (!succeeded) { AssertPrimaryResourceExists(null); } }
/// <inheritdoc /> public virtual Task <TResource> GetForCreateAsync(TId id, CancellationToken cancellationToken) { var resource = _resourceFactory.CreateInstance <TResource>(); resource.Id = id; return(Task.FromResult(resource)); }
public void BeforeReadSingle <TResource, TId>(TId id, ResourcePipeline pipeline) where TResource : class, IIdentifiable <TId> { var temporaryResource = _resourceFactory.CreateInstance <TResource>(); temporaryResource.Id = id; _resourceHookExecutor.BeforeRead <TResource>(pipeline, temporaryResource.StringId); }
/// <inheritdoc /> public virtual async Task <bool> DeleteAsync(TId id) { _logger.LogTrace($"Entering {nameof(DeleteAsync)}('{id}')."); var resourceToDelete = _resourceFactory.CreateInstance <TResource>(); resourceToDelete.Id = id; var resourceFromCache = _dbContext.GetTrackedEntity(resourceToDelete); if (resourceFromCache != null) { resourceToDelete = resourceFromCache; } else { _dbContext.Attach(resourceToDelete); } _dbContext.Remove(resourceToDelete); try { await _dbContext.SaveChangesAsync(); return(true); } catch (DbUpdateConcurrencyException) { return(false); } }
private string DeObfuscateStringId(Type resourceType, string stringId) { var tempResource = _resourceFactory.CreateInstance(resourceType); tempResource.StringId = stringId; return(tempResource.GetTypedId().ToString()); }
public static string GetResourceStringId <TResource, TId>(TId id, IResourceFactory resourceFactory) where TResource : class, IIdentifiable <TId> { TResource tempResource = resourceFactory.CreateInstance <TResource>(); tempResource.Id = id; return(tempResource.StringId); }
public static object ConvertStringIdToTypedId(Type resourceType, string stringId, IResourceFactory resourceFactory) { var tempResource = (IIdentifiable)resourceFactory.CreateInstance(resourceType); tempResource.StringId = stringId; return(GetResourceTypedId(tempResource)); }
/// <summary> /// Traverses through the provided resource and sets the value of the relationship on the other side of the through type. /// In the example described above, this would be the value of "Articles.ArticleTags.Tag". /// </summary> public override void SetValue(object resource, object newValue, IResourceFactory resourceFactory) { if (resource == null) { throw new ArgumentNullException(nameof(resource)); } if (resourceFactory == null) { throw new ArgumentNullException(nameof(resourceFactory)); } base.SetValue(resource, newValue, resourceFactory); if (newValue == null) { ThroughProperty.SetValue(resource, null); } else { List <object> throughResources = new List <object>(); foreach (IIdentifiable identifiable in (IEnumerable)newValue) { object throughResource = resourceFactory.CreateInstance(ThroughType); LeftProperty.SetValue(throughResource, resource); RightProperty.SetValue(throughResource, identifiable); throughResources.Add(throughResource); } var typedCollection = TypeHelper.CopyToTypedCollection(throughResources, ThroughProperty.PropertyType); ThroughProperty.SetValue(resource, typedCollection); } }
/// <summary> /// Creates a new placeholder resource, assigns the specified ID, adds it to the change tracker /// in <see cref="EntityState.Unchanged"/> state and registers it for detachment. /// </summary> public TResource CreateForId <TResource, TId>(TId id) where TResource : IIdentifiable <TId> { var placeholderResource = _resourceFactory.CreateInstance <TResource>(); placeholderResource.Id = id; return(CaptureExisting(placeholderResource)); }
/// <inheritdoc /> public virtual async Task <TResource> CreateAsync(TResource resource, CancellationToken cancellationToken) { _traceWriter.LogMethodStart(new { resource }); if (resource == null) { throw new ArgumentNullException(nameof(resource)); } _resourceChangeTracker.SetRequestedAttributeValues(resource); var defaultResource = _resourceFactory.CreateInstance <TResource>(); defaultResource.Id = resource.Id; _resourceChangeTracker.SetInitiallyStoredAttributeValues(defaultResource); _hookExecutor.BeforeCreate(resource); try { await _repositoryAccessor.CreateAsync(resource, cancellationToken); } catch (DataStoreUpdateException) { var existingResource = await TryGetPrimaryResourceByIdAsync(resource.Id, TopFieldSelection.OnlyIdAttribute, cancellationToken); if (existingResource != null) { throw new ResourceAlreadyExistsException(resource.StringId, _request.PrimaryResource.PublicName); } await AssertResourcesToAssignInRelationshipsExistAsync(resource, cancellationToken); throw; } var resourceFromDatabase = await TryGetPrimaryResourceByIdAsync(resource.Id, TopFieldSelection.WithAllAttributes, cancellationToken); AssertPrimaryResourceExists(resourceFromDatabase); _hookExecutor.AfterCreate(resourceFromDatabase); _resourceChangeTracker.SetFinallyStoredAttributeValues(resourceFromDatabase); bool hasImplicitChanges = _resourceChangeTracker.HasImplicitChanges(); if (!hasImplicitChanges) { return(null); } _hookExecutor.OnReturnSingle(resourceFromDatabase, ResourcePipeline.Post); return(resourceFromDatabase); }
/// <summary> /// Creates an instance of the referenced type in <paramref name="data"/> /// and sets its attributes and relationships /// </summary> /// <param name="data"></param> /// <returns>The parsed entity</returns> private IIdentifiable ParseResourceObject(ResourceObject data) { var resourceContext = _contextProvider.GetResourceContext(data.Type); if (resourceContext == null) { throw new InvalidRequestBodyException("Payload includes unknown resource type.", $"The resource '{data.Type}' is not registered on the resource graph. " + "If you are using Entity Framework, make sure the DbSet matches the expected resource name. " + "If you have manually registered the resource, check that the call to AddResource correctly sets the public name.", null); } var entity = (IIdentifiable)_resourceFactory.CreateInstance(resourceContext.ResourceType); entity = SetAttributes(entity, data.Attributes, resourceContext.Attributes); entity = SetRelationships(entity, data.Relationships, resourceContext.Relationships); if (data.Id != null) { entity.StringId = data.Id; } return(entity); }
private async Task UpdateManyToManyAsync(IIdentifiable parent, HasManyThroughAttribute relationship, IEnumerable <string> relationshipIds) { // we need to create a transaction for the HasManyThrough case so we can get and remove any existing // through resources and only commit if all operations are successful var transaction = await _context.GetCurrentOrCreateTransactionAsync(); // ArticleTag ParameterExpression parameter = Expression.Parameter(relationship.ThroughType); // ArticleTag.ArticleId Expression idMember = Expression.Property(parameter, relationship.LeftIdProperty); // article.Id var parentId = TypeHelper.ConvertType(parent.StringId, relationship.LeftIdProperty.PropertyType); Expression target = Expression.Constant(parentId); // ArticleTag.ArticleId.Equals(article.Id) Expression callEquals = Expression.Call(idMember, "Equals", null, target); var lambda = Expression.Lambda <Func <TRelatedResource, bool> >(callEquals, parameter); // TODO: we shouldn't need to do this instead we should try updating the existing? // the challenge here is if a composite key is used, then we will fail to // create due to a unique key violation var oldLinks = _context .Set <TRelatedResource>() .Where(lambda.Compile()) .ToList(); _context.RemoveRange(oldLinks); var newLinks = relationshipIds.Select(x => { var link = _resourceFactory.CreateInstance(relationship.ThroughType); relationship.LeftIdProperty.SetValue(link, TypeHelper.ConvertType(parentId, relationship.LeftIdProperty.PropertyType)); relationship.RightIdProperty.SetValue(link, TypeHelper.ConvertType(x, relationship.RightIdProperty.PropertyType)); return(link); }); _context.AddRange(newLinks); await _context.SaveChangesAsync(); transaction.Commit(); }
/// <inheritdoc /> public override void SetValue(object entity, object newValue, IResourceFactory resourceFactory) { base.SetValue(entity, newValue, resourceFactory); if (newValue == null) { ThroughProperty.SetValue(entity, null); } else { List <object> joinEntities = new List <object>(); foreach (IIdentifiable resource in (IEnumerable)newValue) { object joinEntity = resourceFactory.CreateInstance(ThroughType); LeftProperty.SetValue(joinEntity, entity); RightProperty.SetValue(joinEntity, resource); joinEntities.Add(joinEntity); } var typedCollection = joinEntities.CopyToTypedCollection(ThroughProperty.PropertyType); ThroughProperty.SetValue(entity, typedCollection); } }