Ejemplo n.º 1
0
        public override DbExpression Visit(DbScanExpression expression)
        {
#if DEBUG_VISITS
            System.Diagnostics.Debug.Print("Visit(DbScanExpression): Target.Name={0}", expression.Target.Name);
#endif
            //  If using SSpace:
            //  This method will be called for all query expressions.  If there is a filter included (in a .Where() for example),
            //  Visit(DbFilterExpression) will be called first and our dynamic filters will have already been included.
            //  Otherwise, we do that here.
            //  If using CSpace:
            //  This method will only be called for the initial entity.  Any other references to other entities will be
            //  handled by the Visit(DbPropertyExpression) - this includes filter references and includes.

            var filterList = FindFiltersForEntitySet(expression.Target.ElementType.MetadataProperties);
            System.Diagnostics.Debug.Print("  Found {0} filters", filterList.Count());

            var baseResult = base.Visit(expression);
            if (filterList.Any())
            {
                var binding             = DbExpressionBuilder.Bind(baseResult);
                var newFilterExpression = BuildFilterExpressionWithDynamicFilters(filterList, binding, null);
                if (newFilterExpression != null)
                {
                    //  If not null, a new DbFilterExpression has been created with our dynamic filters.
                    return(newFilterExpression);
                }
            }

            return(baseResult);
        }
        public override DbExpression Visit(DbScanExpression expression)
        {
            var column = SoftDeleteAttribute.GetSoftDeleteColumnName(expression.Target.ElementType);

            if (column != null)
            {
                // Just because the entity has the soft delete annotation doesn't mean that
                // this particular table has the column. This occurs in situation like TPT
                // inheritance mapping and entity splitting where one type maps to multiple
                // tables.
                // We only apply the filter if the column is actually present in this table.
                // If not, then the query is going to be joining to the table that does have
                // the column anyway, so the filter will still be applied.
                var table = (EntityType)expression.Target.ElementType;
                if (table.Properties.Any(p => p.Name == column))
                {
                    var binding = DbExpressionBuilder.Bind(expression);
                    return(DbExpressionBuilder.Filter(
                               binding,
                               DbExpressionBuilder.NotEqual(
                                   DbExpressionBuilder.Property(
                                       DbExpressionBuilder.Variable(binding.VariableType, binding.VariableName),
                                       column),
                                   DbExpression.FromBoolean(true))));
                }
            }

            return(base.Visit(expression));
        }
        public override DbExpression Visit(DbScanExpression expression)
        {
            //  This method will be called for all query expressions.  If there is a filter included (in a .Where() for example),
            //  Visit(DbFilterExpression) will be called first and our dynamic filters will have already been included.
            //  Otherwise, we do that here.

            string entityName = expression.Target.Name;
            var    filterList = expression.Target.ElementType.MetadataProperties
                                .Where(mp => mp.Name.Contains("customannotation:" + DynamicFilterConstants.ATTRIBUTE_NAME_PREFIX))
                                .Select(m => m.Value as DynamicFilterDefinition);

            var baseResult = base.Visit(expression);

            if (filterList.Any())
            {
                var binding             = DbExpressionBuilder.Bind(baseResult);
                var newFilterExpression = BuildFilterExpressionWithDynamicFilters(entityName, filterList, binding, null);
                if (newFilterExpression != null)
                {
                    //  If not null, a new DbFilterExpression has been created with our dynamic filters.
                    return(newFilterExpression);
                }
            }

            return(baseResult);
        }
Ejemplo n.º 4
0
        public override DbExpression Visit(DbScanExpression expression)
        {
            expression = (DbScanExpression)base.Visit(expression);

            var column = UserAwareAttribute.GetUserColumnName(expression.Target.ElementType);

            if (!string.IsNullOrEmpty(column))
            {
                // Check that there is an authenticated user in this context
                var identity = System.Threading.Thread.CurrentPrincipal.Identity as System.Security.Claims.ClaimsIdentity;
                if (identity == null)
                {
                    throw new System.Security.SecurityException("Unauthenticated access");
                }
                var userIdclaim = identity.Claims.SingleOrDefault(c => c.Type == System.Security.Claims.ClaimTypes.NameIdentifier);
                if (userIdclaim == null)
                {
                    throw new System.Security.SecurityException("Unauthenticated access");
                }

                // Get the current expression binding
                var currentExpressionBinding = DbExpressionBuilder.Bind(expression);
                var newFilterExpression      = BuildFilterExpression(currentExpressionBinding, column);
                if (newFilterExpression != null)
                {
                    //  If not null, a new DbFilterExpression has been created with our dynamic filters.
                    return(newFilterExpression);
                }
            }

            return(expression);
        }
        public override DbExpression Visit(DbScanExpression expression)
        {
            var column = EdmHelper.GetFactoryColumnName(expression.Target.ElementType);

            if (!string.IsNullOrEmpty(column))
            {
                // Get the current expression
                var dbExpression = base.Visit(expression);
                // Get the current expression binding
                var currentExpressionBinding = DbExpressionBuilder.Bind(dbExpression);

                //FactoryId = @Paramname_1
                // Create the variable reference in order to create the property
                var variableReferenceLeftSide = DbExpressionBuilder.Variable(currentExpressionBinding.VariableType,
                                                                             currentExpressionBinding.VariableName);
                // Create the property based on the variable in order to apply the equality
                var tenantPropertyLeftSide = DbExpressionBuilder.Property(variableReferenceLeftSide, column);
                // Create the parameter which is an object representation of a sql parameter.
                // We have to create a parameter and not perform a direct comparison with Equal function for example
                // as this logic is cached per query and called only once
                var tenantParameterLeftSide = DbExpressionBuilder.Parameter(tenantPropertyLeftSide.Property.TypeUsage,
                                                                            FactoryConstants.FactoryIdFilterParameterName);
                // Apply the equality between property and parameter.
                var filterExpressionLeftSide = DbExpressionBuilder.Equal(tenantPropertyLeftSide, tenantParameterLeftSide);

                //1 = @Paramname_2
                // Create the variable reference in order to create the property
                var variableReferenceRightSide = DbExpressionBuilder.Variable(currentExpressionBinding.VariableType,
                                                                              currentExpressionBinding.VariableName);
                // Create the property based on the variable in order to apply the equality
                var tenantPropertyRightSide = DbExpression.FromInt32(1);
                // Create the parameter which is an object representation of a sql parameter.
                // We have to create a parameter and not perform a direct comparison with Equal function for example
                // as this logic is cached per query and called only once
                var tenantParameterRightSide = DbExpressionBuilder.Parameter(TypeUsage.CreateDefaultTypeUsage(PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32)),
                                                                             FactoryConstants.FactoryOverrideFilterParameterName);
                // Apply the equality between property and parameter.
                var filterExpressionRightSide = DbExpressionBuilder.Equal(tenantPropertyRightSide, tenantParameterRightSide);
                DbExpressionBuilder.
                var filterExpression = DbExpressionBuilder.Or(filterExpressionLeftSide, filterExpressionRightSide);

                // Apply the filtering to the initial query
                return(DbExpressionBuilder.Filter(currentExpressionBinding, filterExpression));
            }

            return(base.Visit(expression));
        }
Ejemplo n.º 6
0
        public override DbExpression Visit(DbScanExpression expression)
        {
            var column = TenantAwareAttribute.GetTenantColumnName(expression.Target.ElementType);

            if (!_injectedDynamicFilter && !string.IsNullOrEmpty(column))
            {
                // Get the current expression
                var dbExpression = base.Visit(expression);
                // Get the current expression binding
                var currentExpressionBinding = DbExpressionBuilder.Bind(dbExpression);
                var newFilterExpression      = BuildFilterExpression(currentExpressionBinding, null, column);
                if (newFilterExpression != null)
                {
                    //  If not null, a new DbFilterExpression has been created with our dynamic filters.
                    return(base.Visit(newFilterExpression));
                }
            }

            return(base.Visit(expression));
        }
Ejemplo n.º 7
0
        public override DbExpression Visit(DbScanExpression expression)
        {
            var column = TenantAwareAttribute.GetColumnName(expression.Target.ElementType);

            if (column != null)
            {
                var binding = DbExpressionBuilder.Bind(expression);
                return(DbExpressionBuilder.Filter(
                           binding,
                           DbExpressionBuilder.NotEqual(
                               DbExpressionBuilder.Property(
                                   DbExpressionBuilder.Variable(binding.VariableType, binding.VariableName),
                                   column),
                               DbExpression.FromInt16(1))));
            }
            else
            {
                return(base.Visit(expression));
            }
        }
Ejemplo n.º 8
0
        public override DbExpression Visit(DbScanExpression expression)
        {
            var column = SoftDeleteAttribute.GetSoftDeleteColumnName(expression.Target.ElementType);

            if (column != null)
            {
                var table = (EntityType)expression.Target.ElementType;
                if (table.Properties.Any(p => p.Name == column))
                {
                    var binding = DbExpressionBuilder.Bind(expression);
                    return(DbExpressionBuilder.Filter(
                               binding,
                               DbExpressionBuilder.NotEqual(
                                   DbExpressionBuilder.Property(
                                       DbExpressionBuilder.Variable(binding.VariableType, binding.VariableName),
                                       column),
                                   DbExpression.FromBoolean(true))));
                }
            }
            return(base.Visit(expression));
        }
Ejemplo n.º 9
0
        public override DbExpression Visit(DbOfTypeExpression expression)
        {
#if DEBUG_VISITS
            System.Diagnostics.Debug.Print("Visit(DbOfTypeExpression): OfType={0}", expression.OfType.EdmType.Name);
#endif

            //  This visitor is called for TPH & TPT entities that need to map from base entity type to the
            //  actual type.  Argument contains the base type expression (i.e. User) and OfType contains the
            //  derived type (i.e. Student).
            //  We need to check for any filters that are defined only on the derived type and apply those filters
            //  here - they will not be detected during the DbScanExpression visitor because those filters will not
            //  exist on the base type.
            //  Filters defined on the base type will be found on both entities.  So we only want to apply the filter
            //  that are defined on the OfType entity that are not defined on the Argument entity (as those will be
            //  applied during the DbScanExpression visitor).
            IEnumerable <DynamicFilterDefinition> scanFilterList = null;
            var scanExp = expression.Argument as DbScanExpression;
            if (scanExp != null)
            {
                scanFilterList = FindFiltersForEntitySet(scanExp.Target.ElementType.MetadataProperties);
            }
            var ofTypeFilterList = FindFiltersForEntitySet(expression.OfType.EdmType.MetadataProperties);
            var filtersToApply   = ofTypeFilterList.Where(f => (scanFilterList == null) || !scanFilterList.Any(f2 => f2.ID == f.ID));

            var baseResult = base.Visit(expression);

            if (filtersToApply.Any())
            {
                var binding             = DbExpressionBuilder.Bind(baseResult);
                var newFilterExpression = BuildFilterExpressionWithDynamicFilters(filtersToApply, binding, null);
                if (newFilterExpression != null)
                {
                    //  If not null, a new DbFilterExpression has been created with our dynamic filters.
                    return(newFilterExpression);
                }
            }

            return(baseResult);
        }
Ejemplo n.º 10
0
        public override DbExpression Visit(DbScanExpression expression)
        {
            expression = (DbScanExpression)base.Visit(expression);

            var column = UserAwareAttribute.GetUserColumnName(expression.Target.ElementType);

            if (!string.IsNullOrEmpty(column))
            {
                // Validate user
                Security.ValidateCurrentUser();

                // Get the current expression binding
                var currentExpressionBinding = DbExpressionBuilder.Bind(expression);
                var newFilterExpression      = BuildFilterExpression(currentExpressionBinding, column);
                if (newFilterExpression != null)
                {
                    //  If not null, a new DbFilterExpression has been created with our dynamic filters.
                    return(newFilterExpression);
                }
            }

            return(expression);
        }
Ejemplo n.º 11
0
        public override DbExpression Visit(DbScanExpression expression)
        {
            //  This method will be called for all query expressions.  If there is a filter included (in a .Where() for example),
            //  Visit(DbFilterExpression) will be called first and our dynamic filters will have already been included.
            //  Otherwise, we do that here.

            string entityName = expression.Target.Name;
            var    filterList = FindFiltersForEntitySet(expression.Target.ElementType.MetadataProperties, expression.Target.EntityContainer);

            var baseResult = base.Visit(expression);

            if (filterList.Any())
            {
                var binding             = DbExpressionBuilder.Bind(baseResult);
                var newFilterExpression = BuildFilterExpressionWithDynamicFilters(entityName, filterList, binding, null);
                if (newFilterExpression != null)
                {
                    //  If not null, a new DbFilterExpression has been created with our dynamic filters.
                    return(newFilterExpression);
                }
            }

            return(baseResult);
        }
Ejemplo n.º 12
0
        //  This is called for any navigation property reference so we can apply filters for those entities here.
        //  That includes any navigation properties referenced in functions (.Where() clauses) and also any
        //  child entities that are .Include()'d.
        public override DbExpression Visit(DbPropertyExpression expression)
        {
#if DEBUG_VISITS
            System.Diagnostics.Debug.Print("Visit(DbPropertyExpression): EdmType.Name={0}", expression.ResultType.ModelTypeUsage.EdmType.Name);
#endif
            var baseResult = base.Visit(expression);

            var basePropertyResult = baseResult as DbPropertyExpression;
            if (basePropertyResult == null)
            {
                return(baseResult);      //  base.Visit changed type!
            }
            var navProp = basePropertyResult.Property as NavigationProperty;
            if (navProp != null)
            {
                var targetEntityType = navProp.ToEndMember.GetEntityType();

                var containers = _ObjectContext.MetadataWorkspace.GetItems <EntityContainer>(DataSpace.CSpace).First();
                var filterList = FindFiltersForEntitySet(targetEntityType.MetadataProperties);

                if (filterList.Any())
                {
                    //  If the expression contains a collection (i.e. the child property is an IEnumerable), we can bind directly to it.
                    //  Otherwise, we have to create a DbScanExpression over the ResultType in order to bind.
                    if (baseResult.ResultType.EdmType.BuiltInTypeKind == BuiltInTypeKind.CollectionType)
                    {
                        var binding             = DbExpressionBuilder.Bind(baseResult);
                        var newFilterExpression = BuildFilterExpressionWithDynamicFilters(filterList, binding, null);
                        if (newFilterExpression != null)
                        {
                            //  If not null, a new DbFilterExpression has been created with our dynamic filters.
                            return(newFilterExpression);
                        }
                    }
                    else if (baseResult.ResultType.EdmType.BuiltInTypeKind == BuiltInTypeKind.EntityType)
                    {
                        if (DoesNotSupportElementMethod(_DbContext))
                        {
                            //  Oracle and MySQL do not support the "newFilterExpression.Element()" method that we need to call
                            //  at the end of this block.  Oracle *MAY* support it in a newer release but not sure
                            //  (see https://community.oracle.com/message/10168766#10168766).
                            //  But users may not have the option of upgrading their database so decided to try to support it.
                            //  If we find it is supported by newer versions, can detect those versions and allow the normal handling.
                            //  To apply any necessary filters to these entities, we're going to have to do it using SSpace.
                            //  These entities will be visited via the DbScan visit method so we will apply filters there.
                            //  If one of those filters then references a child property, the filter will fail.
                            return(baseResult);
                        }

                        DbExpression scanExpr;

                        var entitySet = containers.EntitySets.FirstOrDefault(e => e.ElementType.Name == baseResult.ResultType.EdmType.Name);
                        if (entitySet == null)
                        {
                            if (baseResult.ResultType.EdmType.BaseType == null)
                            {
                                throw new ApplicationException(string.Format("EntitySet not found for {0}", baseResult.ResultType.EdmType.Name));
                            }

                            //  Did not find the entity set for the property but it has a base type.
                            //  This means the entity set of the property is a derived class of a TPT base class.
                            //  Find the entity set of the parent and then map it to the type we need.
                            //  Then we can bind against that expression.
                            entitySet = containers.EntitySets.FirstOrDefault(e => e.ElementType.Name == baseResult.ResultType.EdmType.BaseType.Name);
                            if (entitySet == null)        //  hope we don't need to do this recursively...
                            {
                                throw new ApplicationException(string.Format("EntitySet not found for {0} or BaseType {1}", baseResult.ResultType.EdmType.Name, baseResult.ResultType.EdmType.BaseType.Name));
                            }

                            var parentScanExpr = DbExpressionBuilder.Scan(entitySet);
                            scanExpr = DbExpressionBuilder.OfType(parentScanExpr, baseResult.ResultType);
                        }
                        else
                        {
                            scanExpr = DbExpressionBuilder.Scan(entitySet);
                        }

                        var binding = DbExpressionBuilder.Bind(scanExpr);

                        //  Build the join conditions that are needed to join from the source object (basePropertyResult.Instance)
                        //  to the child object (the scan expression we just creating the binding for).
                        //  These conditions will be and'd with the filter conditions.
                        var associationType = navProp.RelationshipType as AssociationType;
                        if (associationType == null)
                        {
                            throw new ApplicationException(string.Format("Unable to find AssociationType on navigation property of single child property {0} in type {1}", navProp.Name, navProp.DeclaringType.FullName));
                        }
                        if (associationType.Constraint == null)
                        {
                            //  KNOWN_ISSUE:
                            //  If this happens, the model does not contain the foreign key (the "id" property).  EF will automatically generate
                            //  it based on naming rules when generating the SSpace/database models but does not expose the Constraint here in the
                            //  AssociationType.  In order for us to be able to generate the conditions correctly, those Foreign Keys need to be
                            //  specified on the model.  To fix/handle this, we would need to examine the SSpace Association Sets (which do have
                            //  these relations!!) to try to map that information back to CSpace to figure out the correct properties of the FK conditions.
                            //  or...the models just need to contain the necessary "ID" properties for the FK relations so that they are available here
                            //  (in CSpace) for us to generate the necessary join conditions.
                            throw new ApplicationException(string.Format("FK Constriant not found for association '{0}' - must directly specify foreign keys on model to be able to apply this filter", associationType.FullName));
                        }

                        //  Figure out if the "baseResults" are the from side or to side of the constraint so we can create the properties correctly
                        //  Note that this navigation property may be the same type as parent entity (so both association types
                        //  will be the same type).  In that case, we need to figure out which side of the association matches the
                        //  PKs of the main entity.
                        var  fromEdmType = ((AssociationEndMember)associationType.Constraint.FromRole).GetEntityType();
                        var  toEdmType   = ((AssociationEndMember)associationType.Constraint.ToRole).GetEntityType();
                        bool baseResultIsFromRole;
                        if (fromEdmType != toEdmType)
                        {
                            baseResultIsFromRole = (basePropertyResult.Instance.ResultType.EdmType == fromEdmType);
                        }
                        else
                        {
                            //  When same, basePropertyResult is the child property and binding is the main entity.
                            //  Fixes issue #85.
                            baseResultIsFromRole = false;
                        }

                        DbExpression joinCondition = null;
                        for (int i = 0; i < associationType.Constraint.FromProperties.Count; i++)
                        {
                            var prop1 = DbExpressionBuilder.Property(basePropertyResult.Instance, baseResultIsFromRole ? associationType.Constraint.FromProperties[i] : associationType.Constraint.ToProperties[i]);
                            var prop2 = DbExpressionBuilder.Property(binding.Variable, baseResultIsFromRole ? associationType.Constraint.ToProperties[i] : associationType.Constraint.FromProperties[i]);

                            var condition = prop1.Equal(prop2) as DbExpression;
                            joinCondition = (joinCondition == null) ? condition : joinCondition.And(condition);
                        }

                        //  Translate the filter predicate into a DbExpression bound to the Scan expression of the target entity set.
                        //  Those conditions are then and'd with the join conditions necessary to join the target table with the source table.
                        var newFilterExpression = BuildFilterExpressionWithDynamicFilters(filterList, binding, joinCondition);
                        if (newFilterExpression != null)
                        {
                            //  Converts the collection results into a single row.  The expected output is a single item so EF will
                            //  then populate the results of that query into the property in the model.
                            //  The resulting SQL will be a normal "left outer join" just as it would normally be except that our
                            //  filter predicate conditions will be included with the normal join conditions.

                            //  MySQL needs this Limit() applied here or it throws an error saying:
                            //  Unable to cast object of type 'MySql.Data.Entity.SelectStatement' to type 'MySql.Data.Entity.LiteralFragment'.
                            //  But don't do that unless necessary because it produces extra "outer apply" sub queries in MS SQL.
                            //  This trick does not work for Oracle...
                            if (_DbContext.IsMySql())
                            {
                                return(newFilterExpression.Limit(DbConstantExpression.FromInt32(1)).Element());
                            }

                            return(newFilterExpression.Element());
                        }
                    }
                }
            }

            return(baseResult);
        }