Esempio n. 1
0
        public EntityMetadataColumnSetupProvider(IEntityType entity, EntityState state, BulkOptions bulkOptions)
        {
            _bulkOptions = bulkOptions;

            SchemaName = entity.GetSchema();
            TableName  = entity.GetTableName();

            var properties = entity.GetProperties();

            if (state == EntityState.Deleted)
            {
                properties = properties.Where(p => p.IsPrimaryKey());
            }

            if (_bulkOptions.ShadowPropertyAccessor == null)
            {
                properties = properties.Where(p => entity.FindDiscriminatorProperty() == p || !p.IsShadowProperty());
            }

            var columns = properties.Select((p, i) => CreateColumnSetup(entity, p, i, state, _bulkOptions)).Where(p => p.ValueDirection != ValueDirection.None);

            if (!bulkOptions.PropagateValues)
            {
                columns = columns.Where(p => p.ValueDirection.HasFlag(ValueDirection.Write));
            }

            _columns = columns.ToImmutableList();
        }
Esempio n. 2
0
    /// <summary>
    ///     Validates the discriminator and values for all entity types derived from the given one.
    /// </summary>
    /// <param name="rootEntityType">The entity type to validate.</param>
    protected virtual void ValidateDiscriminatorValues(IEntityType rootEntityType)
    {
        var derivedTypes = rootEntityType.GetDerivedTypesInclusive().ToList();

        if (derivedTypes.Count == 1)
        {
            return;
        }

        var discriminatorProperty = rootEntityType.FindDiscriminatorProperty();

        if (discriminatorProperty == null)
        {
            throw new InvalidOperationException(
                      CoreStrings.NoDiscriminatorProperty(rootEntityType.DisplayName()));
        }

        var discriminatorValues = new Dictionary <object, IEntityType>(discriminatorProperty.GetKeyValueComparer());

        foreach (var derivedType in derivedTypes)
        {
            if (!derivedType.ClrType.IsInstantiable())
            {
                continue;
            }

            var discriminatorValue = derivedType.GetDiscriminatorValue();
            if (discriminatorValue == null)
            {
                throw new InvalidOperationException(
                          CoreStrings.NoDiscriminatorValue(derivedType.DisplayName()));
            }

            if (discriminatorValues.TryGetValue(discriminatorValue, out var duplicateEntityType))
            {
                throw new InvalidOperationException(
                          CoreStrings.DuplicateDiscriminatorValue(
                              derivedType.DisplayName(), discriminatorValue, duplicateEntityType.DisplayName()));
            }

            discriminatorValues[discriminatorValue] = derivedType;
        }
    }
Esempio n. 3
0
 public static IProperty?GetDiscriminatorProperty(this IEntityType entityType)
 => entityType.FindDiscriminatorProperty();
Esempio n. 4
0
    /// <inheritdoc />
    protected override LambdaExpression GenerateMaterializationCondition(IEntityType entityType, bool nullable)
    {
        LambdaExpression baseCondition;

        if (entityType.FindDiscriminatorProperty() == null &&
            entityType.GetDirectlyDerivedTypes().Any())
        {
            // TPT
            var valueBufferParameter       = Parameter(typeof(ValueBuffer));
            var discriminatorValueVariable = Variable(typeof(string), "discriminator");
            var expressions = new List <Expression>
            {
                Assign(
                    discriminatorValueVariable,
                    valueBufferParameter.CreateValueBufferReadValueExpression(typeof(string), 0, null))
            };

            var derivedConcreteEntityTypes = entityType.GetDerivedTypes().Where(dt => !dt.IsAbstract()).ToArray();
            var switchCases = new SwitchCase[derivedConcreteEntityTypes.Length];
            for (var i = 0; i < derivedConcreteEntityTypes.Length; i++)
            {
                var discriminatorValue = Constant(derivedConcreteEntityTypes[i].ShortName(), typeof(string));
                switchCases[i] = SwitchCase(Constant(derivedConcreteEntityTypes[i], typeof(IEntityType)), discriminatorValue);
            }

            var defaultBlock = entityType.IsAbstract()
                ? CreateUnableToDiscriminateExceptionExpression(entityType, discriminatorValueVariable)
                : Constant(entityType, typeof(IEntityType));

            expressions.Add(Switch(discriminatorValueVariable, defaultBlock, switchCases));
            baseCondition = Lambda(Block(new[] { discriminatorValueVariable }, expressions), valueBufferParameter);
        }
        else
        {
            baseCondition = base.GenerateMaterializationCondition(entityType, nullable);
        }

        if (entityType.FindPrimaryKey() != null)
        {
            var table = entityType.GetViewOrTableMappings().FirstOrDefault()?.Table;
            if (table != null &&
                table.IsOptional(entityType))
            {
                // Optional dependent
                var        body = baseCondition.Body;
                var        valueBufferParameter    = baseCondition.Parameters[0];
                Expression?condition               = null;
                var        requiredNonPkProperties = entityType.GetProperties().Where(p => !p.IsNullable && !p.IsPrimaryKey()).ToList();
                if (requiredNonPkProperties.Count > 0)
                {
                    condition = requiredNonPkProperties
                                .Select(
                        p => NotEqual(
                            valueBufferParameter.CreateValueBufferReadValueExpression(typeof(object), p.GetIndex(), p),
                            Constant(null)))
                                .Aggregate((a, b) => AndAlso(a, b));
                }

                var allNonPrincipalSharedNonPkProperties = entityType.GetNonPrincipalSharedNonPkProperties(table);
                // We don't need condition for nullable property if there exist at least one required property which is non shared.
                if (allNonPrincipalSharedNonPkProperties.Count != 0 &&
                    allNonPrincipalSharedNonPkProperties.All(p => p.IsNullable))
                {
                    var atLeastOneNonNullValueInNullablePropertyCondition = allNonPrincipalSharedNonPkProperties
                                                                            .Select(
                        p => NotEqual(
                            valueBufferParameter.CreateValueBufferReadValueExpression(typeof(object), p.GetIndex(), p),
                            Constant(null)))
                                                                            .Aggregate((a, b) => OrElse(a, b));

                    condition = condition == null
                        ? atLeastOneNonNullValueInNullablePropertyCondition
                        : AndAlso(condition, atLeastOneNonNullValueInNullablePropertyCondition);
                }

                if (condition != null)
                {
                    body = Condition(condition, body, Default(typeof(IEntityType)));
                }

                return(Lambda(body, valueBufferParameter));
            }
        }

        return(baseCondition);
    }
        /// <summary>
        ///     Creates an expression of <see cref="Func{ValueBuffer, IEntityType}" /> to determine which entity type to materialize.
        /// </summary>
        /// <param name="entityType">The entity type to create materialization condition for.</param>
        /// <param name="nullable">Whether this entity instance can be null.</param>
        /// <returns>An expression of <see cref="Func{ValueBuffer, IEntityType}" /> representing materilization condition for the entity type.</returns>
        protected virtual LambdaExpression GenerateMaterializationCondition(IEntityType entityType, bool nullable)
        {
            Check.NotNull(entityType, nameof(EntityType));

            var        valueBufferParameter = Parameter(typeof(ValueBuffer));
            Expression body;
            var        concreteEntityTypes   = entityType.GetConcreteDerivedTypesInclusive().ToArray();
            var        discriminatorProperty = entityType.FindDiscriminatorProperty();

            if (discriminatorProperty != null)
            {
                var discriminatorValueVariable = Variable(discriminatorProperty.ClrType, "discriminator");
                var expressions = new List <Expression>
                {
                    Assign(
                        discriminatorValueVariable,
                        valueBufferParameter.CreateValueBufferReadValueExpression(
                            discriminatorProperty.ClrType, discriminatorProperty.GetIndex(), discriminatorProperty))
                };

                var exception = CreateUnableToDiscriminateExceptionExpression(entityType, discriminatorValueVariable);

                var discriminatorComparer = discriminatorProperty.GetKeyValueComparer();
                if (discriminatorComparer.IsDefault())
                {
                    var switchCases = new SwitchCase[concreteEntityTypes.Length];
                    for (var i = 0; i < concreteEntityTypes.Length; i++)
                    {
                        var discriminatorValue = Constant(concreteEntityTypes[i].GetDiscriminatorValue(), discriminatorProperty.ClrType);
                        switchCases[i] = SwitchCase(Constant(concreteEntityTypes[i], typeof(IEntityType)), discriminatorValue);
                    }

                    expressions.Add(Switch(discriminatorValueVariable, exception, switchCases));
                }
                else
                {
                    Expression conditions = exception;
                    for (var i = concreteEntityTypes.Length - 1; i >= 0; i--)
                    {
                        conditions = Condition(
                            discriminatorComparer.ExtractEqualsBody(
                                discriminatorValueVariable,
                                Constant(
                                    concreteEntityTypes[i].GetDiscriminatorValue(),
                                    discriminatorProperty.ClrType)),
                            Constant(concreteEntityTypes[i], typeof(IEntityType)),
                            conditions);
                    }

                    expressions.Add(conditions);
                }

                body = Block(new[] { discriminatorValueVariable }, expressions);
            }
            else
            {
                body = Constant(concreteEntityTypes.Length == 1 ? concreteEntityTypes[0] : entityType, typeof(IEntityType));
            }

            if (entityType.FindPrimaryKey() == null &&
                nullable)
            {
                body = Condition(
                    entityType.GetProperties()
                    .Select(
                        p => NotEqual(
                            valueBufferParameter.CreateValueBufferReadValueExpression(typeof(object), p.GetIndex(), p),
                            Constant(null)))
                    .Aggregate((a, b) => OrElse(a, b)),
                    body,
                    Default(typeof(IEntityType)));
            }

            return(Lambda(body, valueBufferParameter));
        }
Esempio n. 6
0
        private IColumnSetup CreateColumnSetup(IEntityType entity, IProperty property, int index, EntityState state, BulkOptions bulkOptions)
        {
            var storeIdentifier = StoreObjectIdentifier.Create(entity, StoreObjectType.Table);

            var direction = GetValueDirection(property, state);

            if (property.IsPrimaryKey() && _bulkOptions.IdentityInsert)
            {
                direction = ValueDirection.Write;
            }

            if (!bulkOptions.PropagateValues)
            {
                direction = direction & ~ValueDirection.Read;
            }

            if (entity.FindDiscriminatorProperty() == property)
            {
                var discriminatorValue = entity.GetDiscriminatorValue();
                return(new DelegateColumnSetup(index, property.GetColumnName(storeIdentifier.Value), property.ClrType, p => discriminatorValue, (p, q) => { }, ValueDirection.Write));
            }

            Expression <Func <object, object> >   getValue = null;
            Expression <Action <object, object> > setValue = null;

            var valueConverter = property.GetValueConverter();

            if (property.IsShadowProperty())
            {
                var accessorType = typeof(IShadowPropertyAccessor);

                var param  = Expression.Parameter(typeof(object), "p");
                var param2 = Expression.Parameter(typeof(object), "q");

                Expression getValueBody = Expression.Convert(Expression.Call(
                                                                 Expression.Constant(bulkOptions.ShadowPropertyAccessor, accessorType),
                                                                 accessorType.GetRuntimeMethod("GetValue", new[] { typeof(object), typeof(string) }),
                                                                 param,
                                                                 Expression.Constant(property.Name)),
                                                             property.ClrType);

                Expression setValueBody = param2;

                if (!bulkOptions.IgnoreDefaultValues)
                {
                    getValueBody = ProcessDefaultValue(getValueBody, property);
                }

                if (valueConverter != null)
                {
                    getValueBody = valueConverter.ConvertToProviderExpression.Body.Replace(valueConverter.ConvertToProviderExpression.Parameters[0], getValueBody);
                    setValueBody = Expression.Convert(valueConverter.ConvertFromProviderExpression.Body.Replace(valueConverter.ConvertFromProviderExpression.Parameters[0], Expression.Convert(setValueBody, valueConverter.ProviderClrType)), typeof(object));
                }

                getValue = Expression.Lambda <Func <object, object> >(
                    Expression.Convert(getValueBody, typeof(object)),
                    param);
                setValue = Expression.Lambda <Action <object, object> >(
                    Expression.Call(
                        Expression.Constant(bulkOptions.ShadowPropertyAccessor, accessorType),
                        accessorType.GetRuntimeMethod("StoreValue", new[] { typeof(object), typeof(string), typeof(object) }),
                        param,
                        Expression.Constant(property.Name), setValueBody),
                    param,
                    param2);
            }
            else
            {
                var param  = Expression.Parameter(typeof(object), "p");
                var param2 = Expression.Parameter(typeof(object), "q");

                var cast = Expression.Convert(param, property.DeclaringEntityType.ClrType);

                Expression getValueBody = Expression.Property(cast, property.PropertyInfo);
                Expression setValueBody = Expression.Convert(param2, property.ClrType);

                if (!bulkOptions.IgnoreDefaultValues)
                {
                    getValueBody = ProcessDefaultValue(getValueBody, property);
                }

                if (valueConverter != null)
                {
                    getValueBody = valueConverter.ConvertToProviderExpression.Body.Replace(valueConverter.ConvertToProviderExpression.Parameters[0], getValueBody);
                    setValueBody = valueConverter.ConvertFromProviderExpression.Body.Replace(valueConverter.ConvertFromProviderExpression.Parameters[0], Expression.Convert(param2, valueConverter.ProviderClrType));
                }

                getValue = Expression.Lambda <Func <object, object> >(Expression.Convert(getValueBody, typeof(object)), param);
                setValue = Expression.Lambda <Action <object, object> >(Expression.Assign(Expression.Property(cast, property.PropertyInfo), setValueBody), param, param2);
            }

            var targetType = property.ClrType;

            if (valueConverter != null)
            {
                targetType = valueConverter.ProviderClrType;
            }

            return(new DelegateColumnSetup(index, property.GetColumnName(storeIdentifier.Value), targetType, getValue.Compile(), setValue.Compile(), direction));
        }