/// <summary> /// Construct filter expression for entity. /// </summary> /// <param name="entity">Entity to construct filter expression for.</param> /// <param name="typeOfFilter">Type of filter expression.</param> /// <returns>Filter expression according to entity.</returns> public Expression <Func <TEntity, bool> > ConstructFilterExpression( TEntity entity, FilterType typeOfFilter) { Expression <Func <TEntity, bool> > filterExpression = null; IEnumerable <string> primaryKeyNames = GetPrimaryKeys(); if (primaryKeyNames.Count() == 0) { throw new ArgumentException(string.Format( "'{0}' has no configured primary key.", typeof(TEntity).Name)); } List <Expression> equalityExpressions = new List <Expression>(); IEnumerable <Expression> singleExpressionList; ParameterExpression parameterExp = Expression.Parameter(typeof(TEntity), "m"); Expression pkFilter = null; Expression ukFilter = null; bool primaryKeysHaveDefaultValues = entity.HasDefaultValues(primaryKeyNames); if (!primaryKeysHaveDefaultValues && typeOfFilter != FilterType.OnlyUnique) { // If primary keys do not have their default values // add this check to equlity expression list singleExpressionList = parameterExp .ConstructEqualityExpressions( entity, primaryKeyNames); pkFilter = singleExpressionList.ConstructAndChain(); } if (typeOfFilter != FilterType.OnlyId && (primaryKeysHaveDefaultValues || typeOfFilter != FilterType.IdOptionalUnique)) { IEnumerable <PropertiesWithSource> uniqueProperties = MappingStorage.Instance.UniqueProperties.Where( m => m.SourceType.Equals(entity.GetType())); if (uniqueProperties.Count() > 0) { foreach (PropertiesWithSource unique in uniqueProperties) { /* *********************************************************** * If any of current set of properties * marked as unique is foreign key, * has default value, and appropriate navigation property is not * null and also origin of this foreign * key has any store generated primary key then this * uniqueness must be ignored. * For example if PersonId (int) and DocumentType (short) has been * set as composite unique in PersonDocument and * if PersonId is foreign key to Person, which in its term has * Primary key which is store generated and if there is no navigation * property to Person from PersonDocument or PersonDocument.Person is not null * then PersonId = 0 and DocumentType = 5 should not * be treated as unique, because the real value of PersonId * will be computed when data will be inserted. *********************************************************** */ IGraphEntityTypeManager uniqueSourceTypeManager = ContextFactory .GetEntityTypeManager(unique.SourceType.Name); bool uniquenessMustBeIgnored = false; var uniquePropertyNames = unique.Properties.Select(m => m.Name).ToList(); var uniqueForeignKeys = uniqueSourceTypeManager .GetForeignKeyDetails() .Select(m => new { TargetClass = m.FromDetails.ContainerClass, Keys = m.ToDetails.Keys.Intersect(uniquePropertyNames) }) .Where(m => m.Keys != null && m.Keys.Any()); NavigationDetail navigationDetailsOfCurrent = GetNavigationDetail(); // If unuque property is foreign key if (uniqueForeignKeys != null && uniqueForeignKeys.Any()) { foreach (var uniqueFk in uniqueForeignKeys) { // If foreign key has default value if (uniqueFk.Keys.Any(u => entity.HasDefaultValue(u))) { // Get navigation relation according to foreign key NavigationRelation navigationRelation = navigationDetailsOfCurrent .Relations .FirstOrDefault(r => r.Direction == NavigationDirection.From && r.PropertyTypeName.Equals(uniqueFk.TargetClass) && r.ToKeyNames.Intersect(uniqueFk.Keys).Any()); // If corresponding navigation property is not null // or there is no such navigation property if (navigationRelation == null || entity.GetPropertyValue(navigationRelation.PropertyName) != null) { bool foreignKeyHasStoreGeneratedPrimaryKey = uniqueFk.Keys.Any(k => { // Get origin of foreign key and check // if it has store generated key. string foreignKeyOrigin = uniqueSourceTypeManager .GetOriginOfForeignKey(k); IGraphEntityTypeManager foreignKeyOriginTypeManger = ContextFactory .GetEntityTypeManager(foreignKeyOrigin); return(foreignKeyOriginTypeManger.HasStoreGeneratedKey()); }); // If origin of foreign key has store generated Primary key if (foreignKeyHasStoreGeneratedPrimaryKey) { uniquenessMustBeIgnored = true; break; } } } } } // If uniqueness must be ignored then skip this iteration if (uniquenessMustBeIgnored) { continue; } singleExpressionList = parameterExp .ConstructEqualityExpressions( entity, unique.Properties .Select(m => m.Name).ToList()); equalityExpressions.Add(singleExpressionList.ConstructAndChain()); } if (equalityExpressions.Count > 0) { ukFilter = equalityExpressions.ConstructOrChain(); } } } equalityExpressions.Clear(); if (pkFilter != null) { equalityExpressions.Add(pkFilter); } if (ukFilter != null) { equalityExpressions.Add(ukFilter); } if (equalityExpressions.Count > 0) { Expression filterBaseExpression = typeOfFilter == FilterType.IdAndUnique ? equalityExpressions.ConstructAndChain() : equalityExpressions.ConstructOrChain(); filterExpression = Expression.Lambda <Func <TEntity, bool> >( filterBaseExpression, parameterExp); } return(filterExpression); }