/// <summary> /// Configures a related entity of the given entity. /// </summary> /// <typeparam name="TProperty">The type of the related entity property.</typeparam> /// <typeparam name="TKey">The type of the related entity key.</typeparam> /// <param name="relatedEntityProperty">The related entity property.</param> /// <param name="relatedEntityKey">The related entity key.</param> /// <returns>The configuration ovject of the given entity.</returns> /// <exception cref="System.ArgumentNullException">The <paramref name="relatedEntityProperty"/> is null.</exception> /// <exception cref="System.ArgumentException">The <paramref name="relatedEntityProperty"/> is not an one level property expression.</exception> public RelatedEntityItemConfiguration <TEntity, TProperty> WithEntity <TProperty, TKey>( Expression <Func <TItem, TProperty> > relatedEntityProperty, Expression <Func <TItem, TKey> > relatedEntityKey) where TProperty : class { Error.ArgumentNullException_IfNull(relatedEntityProperty, "relatedEntityProperty"); DAError.ArgumentException_IfNotOneLevelPropertyExpression(relatedEntityProperty); if (relatedEntityKey != null) { DAError.ArgumentException_IfNotOneLevelPropertyExpression(relatedEntityKey); } var memberProperty = ReflectionHelper.GetPropertyName(relatedEntityProperty); var memberKey = relatedEntityKey != null?ReflectionHelper.GetPropertyName(relatedEntityKey) : string.Empty; var newMember = new RelatedEntityInfo( string.Format(newMemberFormat2, currentRelatedEntityInfo.RelatedPropertyPath, memberProperty), string.Format(newMemberFormat2, currentRelatedEntityInfo.RelatedKeyPath, memberKey)); if (!relatedEntityInfo.Contains(newMember)) { relatedEntityInfo.Remove(currentRelatedEntityInfo); relatedEntityInfo.Add(newMember); } return(new RelatedEntityItemConfiguration <TEntity, TProperty>( relatedEntityInfo, newMember, subEntityInfo, usedEntityInfo, usingEntityInfo)); }
/// <summary> /// Initializes the new instance of the <see cref="RelatedEntityItemConfiguration{TEntity,TItem}"/> class. /// </summary> /// <param name="relatedEntityInfo">Information about related entities.</param> /// <param name="currentRelatedEntityInfo">Information about the current related entity to be continued.</param> /// <param name="subEntityInfo">Information about sub entities for the given entity.</param> /// <param name="usedEntityInfo">Information about entities used by the given entity.</param> /// <param name="usingEntityInfo">Information about entities using the given entity.</param> /// <exception cref="System.ArgumentNullException">The <paramref name="relatedEntityInfo"/> or /// <paramref name="currentRelatedEntityInfo"/> or <paramref name="subEntityInfo"/> or /// <paramref name="usedEntityInfo"/> or <paramref name="usingEntityInfo"/> is null.</exception> internal RelatedEntityItemConfiguration(IList <RelatedEntityInfo> relatedEntityInfo, RelatedEntityInfo currentRelatedEntityInfo, IList <RelatedEntityInfo> subEntityInfo, IList <RelatedEntityInfo> usedEntityInfo, IList <RelatedEntityInfo> usingEntityInfo) : base(subEntityInfo, usedEntityInfo, usingEntityInfo) { Error.ArgumentNullException_IfNull(relatedEntityInfo, "currentEntityInfo"); Error.ArgumentNullException_IfNull(currentRelatedEntityInfo, "currentRelatedEntityInfo"); this.relatedEntityInfo = relatedEntityInfo; this.currentRelatedEntityInfo = currentRelatedEntityInfo; }
/// <summary> /// Combines the two related entity information instances. /// </summary> /// <param name="firstInfo">The first related entity information.</param> /// <param name="secondInfo">The second related entity information.</param> /// <returns>The combined related entity information.</returns> /// <exception cref="System.ArgumentNullException">The <paramref name="firstInfo"/> /// or the <paramref name="secondInfo"/> is null.</exception> public static RelatedEntityInfo Combine(RelatedEntityInfo firstInfo, RelatedEntityInfo secondInfo) { Error.ArgumentNullException_IfNull(firstInfo, "firstInfo"); Error.ArgumentNullException_IfNull(secondInfo, "secondInfo"); if (firstInfo.IsEmpty()) { return(secondInfo); } else if (secondInfo.IsEmpty()) { return(firstInfo); } return(new RelatedEntityInfo(string.Format("{0}.{1}", firstInfo.RelatedPropertyPath, secondInfo.RelatedPropertyPath), string.Format("{0}.{1}", firstInfo.RelatedKeyPath, secondInfo.RelatedKeyPath))); }
/// <summary> /// Combines the two related entity information instances. /// </summary> /// <param name="firstInfo">The first related entity information.</param> /// <param name="secondInfo">The second related entity information.</param> /// <returns>The combined related entity information.</returns> /// <exception cref="System.ArgumentNullException">The <paramref name="firstInfo"/> /// or the <paramref name="secondInfo"/> is null.</exception> public static RelatedEntityInfo Combine(RelatedEntityInfo firstInfo, RelatedEntityInfo secondInfo) { Error.ArgumentNullException_IfNull(firstInfo, "firstInfo"); Error.ArgumentNullException_IfNull(secondInfo, "secondInfo"); if (firstInfo.IsEmpty()) { return secondInfo; } else if (secondInfo.IsEmpty()) { return firstInfo; } return new RelatedEntityInfo(string.Format("{0}.{1}", firstInfo.RelatedPropertyPath, secondInfo.RelatedPropertyPath), string.Format("{0}.{1}", firstInfo.RelatedKeyPath, secondInfo.RelatedKeyPath)); }
/// <summary> /// Configures using entities for the entity. /// </summary> /// <typeparam name="TProperty">The type of the using entities property.</typeparam> /// <param name="usingEntitiesProperty">The using collection.</param> /// <returns>The configuration object to configure a using entities.</returns> /// <exception cref="System.ArgumentNullException">The <paramref name="usingEntitiesProperty"/> is null.</exception> /// <exception cref="System.ArgumentException">The <paramref name="usingEntitiesProperty"/> is not an one level property expression.</exception> public RelatedEntityItemConfiguration <TEntity, TProperty> IsUsedByEntities <TProperty>( Expression <Func <TEntity, ICollection <TProperty> > > usingEntitiesProperty) where TProperty : class { Error.ArgumentNullException_IfNull(usingEntitiesProperty, "usingEntitiesProperty"); DAError.ArgumentException_IfNotOneLevelPropertyExpression(usingEntitiesProperty); var member = new RelatedEntityInfo(ReflectionHelper.GetPropertyName(usingEntitiesProperty), string.Empty); if (!usingEntityInfo.Contains(member)) { usingEntityInfo.Add(member); } return(new RelatedEntityItemConfiguration <TEntity, TProperty>( usingEntityInfo, member, subEntityInfo, usedEntityInfo, usingEntityInfo)); }
/// <summary> /// Configures a sub entity of the entity. /// </summary> /// <typeparam name="TProperty">The type of the sub entity property.</typeparam> /// <typeparam name="TKey">The type of the sub entity key.</typeparam> /// <param name="subEntityProperty">The sub entity property.</param> /// <param name="subEntityKey">The sub entity key.</param> /// <returns>The configuration object for related entities.</returns> /// <exception cref="System.ArgumentNullException">The <paramref name="subEntityProperty"/> is null.</exception> /// <exception cref="System.ArgumentException">The <paramref name="subEntityProperty"/> or /// <paramref name="subEntityKey"/> is not an one level property expression.</exception> public RelatedEntityItemConfiguration <TEntity, TProperty> HasSubEntity <TProperty, TKey>( Expression <Func <TEntity, TProperty> > subEntityProperty, Expression <Func <TEntity, TKey> > subEntityKey) where TProperty : class { Error.ArgumentNullException_IfNull(subEntityProperty, "subEntityProperty"); DAError.ArgumentException_IfNotOneLevelPropertyExpression(subEntityProperty); if (subEntityKey != null) { DAError.ArgumentException_IfNotOneLevelPropertyExpression(subEntityKey); } var member = new RelatedEntityInfo(ReflectionHelper.GetPropertyName(subEntityProperty), subEntityKey != null ? ReflectionHelper.GetPropertyName(subEntityKey) : string.Empty); if (!subEntityInfo.Contains(member)) { subEntityInfo.Add(member); } return(new RelatedEntityItemConfiguration <TEntity, TProperty>( subEntityInfo, member, subEntityInfo, usedEntityInfo, usingEntityInfo)); }
/// <summary> /// Checks if the current information includes the specified information. /// </summary> /// <param name="other">The other.</param> /// <returns><c>true</c> if the current information includes the specified information, otherwise <c>false</c>.</returns> /// <exception cref="System.ArgumentNullException">The <paramref name="other"/> is null.</exception> public bool Includes(RelatedEntityInfo other) { Error.ArgumentNullException_IfNull(other, "other"); return(RelatedPropertyPath.StartsWith(other.RelatedPropertyPath)); }
/// <summary> /// Checks if the current information includes the specified information. /// </summary> /// <param name="other">The other.</param> /// <returns><c>true</c> if the current information includes the specified information, otherwise <c>false</c>.</returns> /// <exception cref="System.ArgumentNullException">The <paramref name="other"/> is null.</exception> public bool Includes(RelatedEntityInfo other) { Error.ArgumentNullException_IfNull(other, "other"); return RelatedPropertyPath.StartsWith(other.RelatedPropertyPath); }
/// <summary> /// Recursively iterates over all the related entities and runs the specified action. /// Iteration is executed in the recursive ascending direction. /// </summary> /// <param name="rootEntity">The root entity.</param> /// <param name="relatedEntityContainer">The related entity container.</param> /// <param name="currentEntityInfo">The current entity information.</param> /// <param name="containerEntityInfo">The container's entity information.</param> /// <param name="direction">A direction of the recursive iteration.</param> /// <param name="action">The action.</param> /// <param name="subEntityInfo">The information about sub entities to skip.</param> private void ForEachRelatedEntity(TEntity rootEntity, object relatedEntityContainer, RelatedEntityInfo currentEntityInfo, RelatedEntityInfo containerEntityInfo, RecursionDirection direction, Action <RelatedEntityActionContext <TEntity> > action, RelatedEntityInfo[] subEntityInfo) { var info = currentEntityInfo.First(); var absoluteInfo = RelatedEntityInfo.Combine(containerEntityInfo, info); //If we're working with used or using entities, then //skip the related entity if it is a part of a sub entity. //Do not call action for sub entities. var callAction = subEntityInfo == null || !subEntityInfo.Any(se => se.Includes(absoluteInfo)); var nextInfo = currentEntityInfo.WithoutFirst(); if (ReflectionHelper.IsInherited <IEnumerable <object> >(relatedEntityContainer.GetType(), info.RelatedPropertyPath)) { var collection = ReflectionHelper.GetPropertyValue <IEnumerable <object> >( relatedEntityContainer, info.RelatedPropertyPath); if (direction == RecursionDirection.Descending) { if (callAction) { action(new RelatedEntityActionContext <TEntity>() { RootEntity = rootEntity, RelatedEntity = collection, RelatedEntityContainer = relatedEntityContainer, RelatedEntityInfo = absoluteInfo, RelatedEntityPropertyInfo = ReflectionHelper.GetPropertyInfo(relatedEntityContainer.GetType(), info.RelatedPropertyPath), RelatedEntityKeyInfo = !string.IsNullOrEmpty(info.RelatedKeyPath) ? ReflectionHelper.GetPropertyInfo(relatedEntityContainer.GetType(), info.RelatedKeyPath) : null }); } collection = ReflectionHelper.GetPropertyValue <IEnumerable <object> >( relatedEntityContainer, info.RelatedPropertyPath); //After the action above the collection can be null if (collection == null) { return; } } //Convert to list because the collection can be modified if (collection != null) { foreach (var item in collection.ToList()) { if (direction == RecursionDirection.Ascending) { if (item != null && !nextInfo.IsEmpty()) { ForEachRelatedEntity(rootEntity, item, nextInfo, absoluteInfo, direction, action, subEntityInfo); } } if (callAction) { action(new RelatedEntityActionContext <TEntity>() { RootEntity = rootEntity, RelatedEntity = item, RelatedEntityContainer = relatedEntityContainer, RelatedEntityInfo = absoluteInfo, RelatedEntityPropertyInfo = ReflectionHelper.GetPropertyInfo(relatedEntityContainer.GetType(), info.RelatedPropertyPath), RelatedEntityKeyInfo = !string.IsNullOrEmpty(info.RelatedKeyPath) ? ReflectionHelper.GetPropertyInfo(relatedEntityContainer.GetType(), info.RelatedKeyPath) : null }); } if (direction == RecursionDirection.Descending) { if (item == null) { continue; } if (!nextInfo.IsEmpty()) { ForEachRelatedEntity(rootEntity, item, nextInfo, absoluteInfo, direction, action, subEntityInfo); } } } } if (direction == RecursionDirection.Ascending) { if (callAction) { action(new RelatedEntityActionContext <TEntity>() { RootEntity = rootEntity, RelatedEntity = collection, RelatedEntityContainer = relatedEntityContainer, RelatedEntityInfo = absoluteInfo, RelatedEntityPropertyInfo = ReflectionHelper.GetPropertyInfo(relatedEntityContainer.GetType(), info.RelatedPropertyPath), RelatedEntityKeyInfo = !string.IsNullOrEmpty(info.RelatedKeyPath) ? ReflectionHelper.GetPropertyInfo(relatedEntityContainer.GetType(), info.RelatedKeyPath) : null }); } } } else { var member = ReflectionHelper.GetPropertyValue <object>(relatedEntityContainer, info.RelatedPropertyPath); if (direction == RecursionDirection.Ascending) { if (member != null && !nextInfo.IsEmpty()) { ForEachRelatedEntity(rootEntity, member, nextInfo, absoluteInfo, direction, action, subEntityInfo); } } if (callAction) { action(new RelatedEntityActionContext <TEntity>() { RootEntity = rootEntity, RelatedEntity = member, RelatedEntityContainer = relatedEntityContainer, RelatedEntityInfo = absoluteInfo, RelatedEntityPropertyInfo = ReflectionHelper.GetPropertyInfo(relatedEntityContainer.GetType(), info.RelatedPropertyPath), RelatedEntityKeyInfo = !string.IsNullOrEmpty(info.RelatedKeyPath) ? ReflectionHelper.GetPropertyInfo(relatedEntityContainer.GetType(), info.RelatedKeyPath) : null }); } if (direction == RecursionDirection.Descending) { member = ReflectionHelper.GetPropertyValue <object>(relatedEntityContainer, info.RelatedPropertyPath); if (member == null) { return; } if (!nextInfo.IsEmpty()) { ForEachRelatedEntity(rootEntity, member, nextInfo, absoluteInfo, direction, action, subEntityInfo); } } } }