public LambdaScopeFactory(LambdaParameterNameFactory nameFactory, HasManyThroughAttribute hasManyThrough = null) { ArgumentGuard.NotNull(nameFactory, nameof(nameFactory)); _nameFactory = nameFactory; _hasManyThrough = hasManyThrough; }
/// <inheritdoc /> public QueryLayer ComposeForHasManyThrough <TId>(HasManyThroughAttribute hasManyThroughRelationship, TId leftId, ICollection <IIdentifiable> rightResourceIds) { var leftResourceContext = _resourceContextProvider.GetResourceContext(hasManyThroughRelationship.LeftType); var leftIdAttribute = GetIdAttribute(leftResourceContext); var rightResourceContext = _resourceContextProvider.GetResourceContext(hasManyThroughRelationship.RightType); var rightIdAttribute = GetIdAttribute(rightResourceContext); var rightTypedIds = rightResourceIds.Select(resource => resource.GetTypedId()).ToArray(); var leftFilter = CreateFilterByIds(new[] { leftId }, leftIdAttribute, null); var rightFilter = CreateFilterByIds(rightTypedIds, rightIdAttribute, null); return(new QueryLayer(leftResourceContext) { Include = new IncludeExpression(new[] { new IncludeElementExpression(hasManyThroughRelationship) }), Filter = leftFilter, Projection = new Dictionary <ResourceFieldAttribute, QueryLayer> { [hasManyThroughRelationship] = new QueryLayer(rightResourceContext) { Filter = rightFilter, Projection = new Dictionary <ResourceFieldAttribute, QueryLayer> { [rightIdAttribute] = null } }, [leftIdAttribute] = null } }); }
public LambdaScope(LambdaParameterNameFactory nameFactory, Type elementType, Expression accessorExpression, HasManyThroughAttribute hasManyThrough) { if (nameFactory == null) { throw new ArgumentNullException(nameof(nameFactory)); } if (elementType == null) { throw new ArgumentNullException(nameof(elementType)); } _parameterNameScope = nameFactory.Create(elementType.Name); Parameter = Expression.Parameter(elementType, _parameterNameScope.Name); if (accessorExpression != null) { Accessor = accessorExpression; } else if (hasManyThrough != null) { Accessor = Expression.Property(Parameter, hasManyThrough.RightProperty); } else { Accessor = Parameter; } HasManyThrough = hasManyThrough; }
private IEnumerable <IIdentifiable> GetHasManyThroughIter(HasManyThroughAttribute hasManyThrough, IEnumerable hasManyNavigationEntity) { foreach (var includedEntity in hasManyNavigationEntity) { var targetValue = hasManyThrough.RightProperty.GetValue(includedEntity) as IIdentifiable; yield return(targetValue); } }
private IEnumerable <IIdentifiable> GetHasManyThrough(IIdentifiable parent, HasManyThroughAttribute hasManyThrough) { var throughProperty = GetRelationship(parent, hasManyThrough.InternalThroughName); if (throughProperty is IEnumerable hasManyNavigationEntity) { // wrap "yield return" in a sub-function so we can correctly return null if the property is null. return(GetHasManyThroughIter(hasManyThrough, hasManyNavigationEntity)); } return(null); }
private IEnumerable <IIdentifiable> GetHasManyThrough(IIdentifiable parent, HasManyThroughAttribute hasManyThrough) { var throughProperty = GetRelationship(parent, hasManyThrough.InternalThroughName); if (throughProperty is IEnumerable hasManyNavigationEntity) { foreach (var includedEntity in hasManyNavigationEntity) { var targetValue = hasManyThrough.RightProperty.GetValue(includedEntity) as IIdentifiable; yield return(targetValue); } } }
private async Task RemoveExistingIdsFromSecondarySet(TId primaryId, ISet <IIdentifiable> secondaryResourceIds, HasManyThroughAttribute hasManyThrough, CancellationToken cancellationToken) { var queryLayer = _queryLayerComposer.ComposeForHasMany(hasManyThrough, primaryId, secondaryResourceIds); var primaryResources = await _repositoryAccessor.GetAsync <TResource>(queryLayer, cancellationToken); var primaryResource = primaryResources.FirstOrDefault(); AssertPrimaryResourceExists(primaryResource); var rightValue = _request.Relationship.GetValue(primaryResource); var existingRightResourceIds = TypeHelper.ExtractResources(rightValue); secondaryResourceIds.ExceptWith(existingRightResourceIds); }
private MemberAssignment CreatePropertyAssignment(PropertySelector selector, LambdaScope lambdaScope) { MemberExpression propertyAccess = Expression.Property(lambdaScope.Accessor, selector.Property); Expression assignmentRightHandSide = propertyAccess; if (selector.NextLayer != null) { HasManyThroughAttribute hasManyThrough = selector.OriginatingField as HasManyThroughAttribute; var lambdaScopeFactory = new LambdaScopeFactory(_nameFactory, hasManyThrough); assignmentRightHandSide = CreateAssignmentRightHandSideForLayer(selector.NextLayer, lambdaScope, propertyAccess, selector.Property, lambdaScopeFactory); } return(Expression.Bind(selector.Property, assignmentRightHandSide)); }
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 // join entities 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 = Activator.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(); }
public LambdaScopeFactory(LambdaParameterNameFactory nameFactory, HasManyThroughAttribute hasManyThrough = null) { _nameFactory = nameFactory ?? throw new ArgumentNullException(nameof(nameFactory)); _hasManyThrough = hasManyThrough; }