Example #1
0
		public static void Bind(this IStatementBase statement, IDataMutateContextBase context, DbCommand command, object data)
		{
			if(data == null || !statement.HasParameters)
				return;

			foreach(var parameter in statement.Parameters)
			{
				var dbParameter = command.Parameters[parameter.Name];

				if(dbParameter.Direction == ParameterDirection.Input || dbParameter.Direction == ParameterDirection.InputOutput)
				{
					if(parameter.Schema == null || parameter.HasValue)
					{
						if(parameter.Value is IDataValueBinder binder)
							dbParameter.Value = binder.Bind(context, data, GetParameterValue(data, parameter.Schema, null));
						else
							dbParameter.Value = parameter.Value;

						/*
						 * 对于Schema不为空(即表示该参数对应有数据成员),同时还设置了参数值的情况,
						 * 说明该参数值是数据提供程序或导航连接所得,因此必须将其值写回对应的数据项中。
						 */
						if(parameter.Schema != null)
							parameter.Schema.Token.SetValue(data, parameter.HasValue ? parameter.Value : dbParameter.Value);
					}
					else if(data != null)
					{
						dbParameter.Value = GetParameterValue(data, parameter.Schema, dbParameter.DbType);
					}
				}

				if(dbParameter.Value == null)
					dbParameter.Value = DBNull.Value;
			}
		}
        public static bool Validate(this IDataMutateContextBase context, DataAccessMethod method, Metadata.IDataEntityProperty property, out object value)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (!context.Options.ValidatorSuppressed)
            {
                var validator = context.Validator;

                if (validator != null)
                {
                    switch (method)
                    {
                    case DataAccessMethod.Insert:
                        return(validator.OnInsert(context, property, out value));

                    case DataAccessMethod.Update:
                        return(validator.OnUpdate(context, property, out value));
                    }
                }
            }

            value = null;
            return(false);
        }
        public bool OnUpdate(IDataMutateContextBase context, IDataEntityProperty property, out object value)
        {
            if (_updates.TryGetValue(property.Name, out var factory))
            {
                return(factory.Invoke(context, out value));
            }

            value = null;
            return(false);
        }
        private static bool TryGetUserId(IDataMutateContextBase context, out object value)
        {
            value = null;

            if (Zongsoft.Services.ApplicationContext.Current?.Principal is Zongsoft.Security.CredentialPrincipal principal && principal.Identity.IsAuthenticated)
            {
                value = principal.Identity.Credential.User.UserId;
            }

            return(value != null);
        }
        private static bool TryGetSiteId(IDataMutateContextBase context, out object value)
        {
            if (Zongsoft.Services.ApplicationContext.Current?.Principal is Zongsoft.Security.CredentialPrincipal principal &&
                principal.Identity.IsAuthenticated &&
                principal.Identity.Credential.HasParameters &&
                principal.Identity.Credential.Parameters.TryGetValue("Zongsoft.Community.UserProfile", out var parameter) &&
                parameter is Models.UserProfile profile)
            {
                value = profile.SiteId;
                return(true);
            }

            value = null;
            return(false);
        }
        private static IEnumerable <IDataDictionary <T> > GetDataDictionaries <T>(this IDataMutateContextBase context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (context.Count < 1)
            {
                return(Array.Empty <IDataDictionary <T> >());
            }

            if (context.IsMultiple)
            {
                return(DataDictionary.GetDictionaries <T>((System.Collections.IEnumerable)context.Data));
            }

            return(new IDataDictionary <T>[] { DataDictionary.GetDictionary <T>(context.Data) });
        }
        internal static IEnumerable <UpsertStatement> BuildUpserts(IDataMutateContextBase context, IDataEntity entity, object data, SchemaMember owner, IEnumerable <SchemaMember> schemas)
        {
            var inherits = entity.GetInherits();

            foreach (var inherit in inherits)
            {
                var statement = new UpsertStatement(inherit, owner);

                foreach (var schema in schemas)
                {
                    if (!inherit.Properties.Contains(schema.Name))
                    {
                        continue;
                    }

                    if (schema.Token.Property.IsSimplex)
                    {
                        var simplex = (IDataEntitySimplexProperty)schema.Token.Property;

                        if (simplex.Sequence != null && simplex.Sequence.IsBuiltin)
                        {
                            statement.Sequence = new SelectStatement(owner?.FullPath);
                            statement.Sequence.Select.Members.Add(SequenceExpression.Current(simplex.Sequence.Name, simplex.Name));
                        }
                        else
                        {
                            //确认当前成员是否有提供的写入值
                            var provided = context.Validate(DataAccessMethod.Insert, simplex, out var value);

                            var field = statement.Table.CreateField(schema.Token);
                            statement.Fields.Add(field);

                            var parameter = Utility.IsLinked(owner, simplex) ?
                                            (
                                provided ?
                                Expression.Parameter(schema.Token.Property.Name, simplex.Type, value) :
                                Expression.Parameter(schema.Token.Property.Name, simplex.Type)
                                            ) :
                                            (
                                provided ?
                                Expression.Parameter(field, schema, value) :
                                Expression.Parameter(field, schema)
                                            );

                            statement.Values.Add(parameter);
                            statement.Parameters.Add(parameter);

                            //处理完新增子句部分,接着再处理修改子句部分
                            if (!simplex.IsPrimaryKey && !simplex.Immutable && Utility.IsGenerateRequired(ref data, schema.Name))
                            {
                                //确认当前成员是否有提供的写入值
                                if (context.Validate(DataAccessMethod.Update, simplex, out value))
                                {
                                    parameter = Expression.Parameter(field, schema, value);
                                    statement.Parameters.Add(parameter);
                                }

                                //如果当前的数据成员类型为递增步长类型则生成递增表达式
                                if (schema.Token.MemberType == typeof(Interval))
                                {
                                    /*
                                     * 注:默认参数类型为对应字段的类型,而该字段类型可能为无符号整数,
                                     * 因此当参数类型为无符号整数并且步长为负数(递减),则可能导致参数类型转换溢出,
                                     * 所以必须将该参数类型重置为有符号整数(32位整数)。
                                     */
                                    parameter.DbType = System.Data.DbType.Int32;

                                    //字段设置项的值为字段加参数的加法表达式
                                    statement.Updation.Add(new FieldValue(field, field.Add(parameter)));
                                }
                                else
                                {
                                    statement.Updation.Add(new FieldValue(field, parameter));
                                }
                            }
                        }
                    }
                    else
                    {
                        //不可变复合属性不支持任何写操作,即在修改操作中不能包含不可变复合属性
                        if (schema.Token.Property.Immutable)
                        {
                            throw new DataException($"The '{schema.FullPath}' is an immutable complex(navigation) property and does not support the upsert operation.");
                        }

                        if (!schema.HasChildren)
                        {
                            throw new DataException($"Missing members that does not specify '{schema.FullPath}' complex property.");
                        }

                        var complex = (IDataEntityComplexProperty)schema.Token.Property;
                        var slaves  = BuildUpserts(
                            context,
                            complex.Foreign,
                            null,
                            schema,
                            schema.Children);

                        foreach (var slave in slaves)
                        {
                            slave.Schema = schema;
                            statement.Slaves.Add(slave);
                        }
                    }
                }

                if (statement.Fields.Count > 0)
                {
                    yield return(statement);
                }
            }
        }
 private static bool TryGetTimestamp(IDataMutateContextBase context, out object value)
 {
     value = DateTime.Now;
     return(true);
 }
        private static IEnumerable <InsertStatement> BuildInserts(IDataMutateContextBase context, IDataEntity entity, SchemaMember owner, IEnumerable <SchemaMember> schemas)
        {
            var inherits = entity.GetInherits();

            foreach (var inherit in inherits)
            {
                var statement = new InsertStatement(inherit, owner);

                foreach (var schema in schemas)
                {
                    if (!inherit.Properties.Contains(schema.Name))
                    {
                        continue;
                    }

                    if (schema.Token.Property.IsSimplex)
                    {
                        var simplex = (IDataEntitySimplexProperty)schema.Token.Property;

                        if (simplex.Sequence != null && simplex.Sequence.IsBuiltin)
                        {
                            statement.Sequence = new SelectStatement(owner?.FullPath);
                            statement.Sequence.Select.Members.Add(SequenceExpression.Current(simplex.Sequence.Name, simplex.Name));
                        }
                        else
                        {
                            //确认当前成员是否有提供的写入值
                            var provided = context.Validate(DataAccessMethod.Insert, simplex, out var value);

                            var field = statement.Table.CreateField(schema.Token);
                            statement.Fields.Add(field);

                            var parameter = Utility.IsLinked(owner, simplex) ?
                                            (
                                provided ?
                                Expression.Parameter(schema.Token.Property.Name, simplex.Type, value) :
                                Expression.Parameter(schema.Token.Property.Name, simplex.Type)
                                            ) :
                                            (
                                provided ?
                                Expression.Parameter(field, schema, value) :
                                Expression.Parameter(field, schema)
                                            );

                            statement.Values.Add(parameter);
                            statement.Parameters.Add(parameter);
                        }
                    }
                    else
                    {
                        if (!schema.HasChildren)
                        {
                            throw new DataException($"Missing members that does not specify '{schema.FullPath}' complex property.");
                        }

                        //不可变复合属性不支持任何写操作,即在新增操作中不能包含不可变复合属性
                        if (schema.Token.Property.Immutable)
                        {
                            throw new DataException($"The '{schema.FullPath}' is an immutable complex(navigation) property and does not support the insert operation.");
                        }

                        var complex = (IDataEntityComplexProperty)schema.Token.Property;

                        //注:在构建一对多的导航属性的UPSERT语句时不能指定容器数据(即data参数值为空),因为批量操作语句不支持在构建阶段绑定到具体数据
                        var upserts = UpsertStatementBuilder.BuildUpserts(context, complex.Foreign, (context.IsMultiple ? null : context.Data), schema, schema.Children);

                        //将新建的语句加入到主语句的从属集中
                        foreach (var upsert in upserts)
                        {
                            statement.Slaves.Add(upsert);
                        }

                        //var slaves = BuildInserts(context, complex.Foreign, schema, schema.Children);
                        //foreach(var slave in slaves)
                        //{
                        //	slave.Schema = schema;
                        //	statement.Slaves.Add(slave);
                        //}
                    }
                }

                if (statement.Fields.Count > 0)
                {
                    yield return(statement);
                }
            }
        }
Example #10
0
        internal static IEnumerable <UpsertStatement> BuildUpserts(IDataMutateContextBase context, IDataEntity entity, object data, SchemaMember owner, IEnumerable <SchemaMember> schemas)
        {
            var inherits = entity.GetInherits();

            //更新当前操作的容器数据
            if (data != null && owner != null)
            {
                /*
                 * 如果从当前容器数据中获取指定成员值失败,则:
                 * 1). 容器数据是集合类型,无法确定从集合中的哪个元素来获取指定成员的值,因此设置上下文数据为空;
                 * 2). 容器数据不是集合类型,则说明指定的成员可能有误或发生了内部错误,因此抛出异常。
                 */

                if (owner.Token.TryGetValue(data, null, out var value))
                {
                    data = value;
                }
                else if (Zongsoft.Common.TypeExtension.IsEnumerable(data.GetType()))
                {
                    data = null;
                }
                else
                {
                    throw new DataException($"Cannot get the specified '{owner.Name}' member from the '{data.GetType().FullName}' type.");
                }
            }

            foreach (var inherit in inherits)
            {
                var statement = new UpsertStatement(inherit, owner);
                var sequences = new List <IDataEntitySimplexProperty>();

                foreach (var schema in schemas)
                {
                    if (!inherit.Properties.Contains(schema.Name))
                    {
                        continue;
                    }

                    if (schema.Token.Property.IsSimplex)
                    {
                        var simplex = (IDataEntitySimplexProperty)schema.Token.Property;

                        if (simplex.Sequence != null && simplex.Sequence.IsBuiltin)
                        {
                            statement.Sequence = new SelectStatement(owner?.FullPath);
                            statement.Sequence.Select.Members.Add(SequenceExpression.Current(simplex.Sequence.Name, simplex.Name));
                        }
                        else
                        {
                            //确认当前成员是否有提供的写入值
                            var provided = context.Validate(DataAccessMethod.Insert, simplex, out var value);

                            var field = statement.Table.CreateField(schema.Token);
                            statement.Fields.Add(field);

                            var parameter = Utility.IsLinked(owner, simplex) ?
                                            (
                                provided ?
                                Expression.Parameter(schema.Token.Property.Name, simplex.Type, value) :
                                Expression.Parameter(schema.Token.Property.Name, simplex.Type)
                                            ) :
                                            (
                                provided ?
                                Expression.Parameter(field, schema, value) :
                                Expression.Parameter(field, schema)
                                            );

                            statement.Values.Add(parameter);
                            statement.Parameters.Add(parameter);

                            /* 开始处理修改子句部分 */

                            //注:可能因为非主键的唯一约束导致新增部分失败,
                            //因此必须对含有外部序列字段的UPSERT语句,增加一个重新获取这些外部序列字段的附属查询语句。
                            if (simplex.Sequence != null && !context.IsMultiple)
                            {
                                sequences.Add(simplex);
                            }

                            //忽略不可变字段和序列字段
                            if (simplex.Immutable || simplex.Sequence != null)
                            {
                                continue;
                            }

                            if (owner == null)
                            {
                                if (!Utility.IsGenerateRequired(ref data, schema.Name))
                                {
                                    continue;
                                }
                            }
                            else
                            {
                                //只有一对一(零)的导航属性才需要验证对应的字段值是否变更过,如果没有变更则忽略当前字段
                                if (owner.Token.Property is IDataEntityComplexProperty complex &&
                                    complex.Multiplicity != DataAssociationMultiplicity.Many &&
                                    !Utility.IsGenerateRequired(ref data, schema.Name))
                                {
                                    continue;
                                }
                            }

                            //确认当前成员是否有提供的写入值
                            if (context.Validate(DataAccessMethod.Update, simplex, out value))
                            {
                                parameter = Expression.Parameter(field, schema, value);
                                statement.Parameters.Add(parameter);
                            }

                            //如果当前的数据成员类型为递增步长类型则生成递增表达式
                            if (schema.Token.MemberType == typeof(Interval))
                            {
                                /*
                                 * 注:默认参数类型为对应字段的类型,而该字段类型可能为无符号整数,
                                 * 因此当参数类型为无符号整数并且步长为负数(递减),则可能导致参数类型转换溢出,
                                 * 所以必须将该参数类型重置为有符号整数(32位整数)。
                                 */
                                parameter.DbType = System.Data.DbType.Int32;

                                //字段设置项的值为字段加参数的加法表达式
                                statement.Updation.Add(new FieldValue(field, field.Add(parameter)));
                            }
                            else
                            {
                                statement.Updation.Add(new FieldValue(field, parameter));
                            }
                        }
                    }
                    else
                    {
                        //不可变复合属性不支持任何写操作,即在修改操作中不能包含不可变复合属性
                        if (schema.Token.Property.Immutable)
                        {
                            throw new DataException($"The '{schema.FullPath}' is an immutable complex(navigation) property and does not support the upsert operation.");
                        }

                        if (!schema.HasChildren)
                        {
                            throw new DataException($"Missing members that does not specify '{schema.FullPath}' complex property.");
                        }

                        var complex = (IDataEntityComplexProperty)schema.Token.Property;
                        var slaves  = BuildUpserts(
                            context,
                            complex.Foreign,
                            data,
                            schema,
                            schema.Children);

                        foreach (var slave in slaves)
                        {
                            slave.Schema = schema;
                            statement.Slaves.Add(slave);
                        }
                    }
                }

                //构建重新获取外部序列字段的附属查询语句
                if (sequences != null && sequences.Count > 0)
                {
                    var selection = new SelectStatement(inherit, owner?.FullPath);

                    for (int i = 0; i < sequences.Count; i++)
                    {
                        selection.Select.Members.Add(selection.CreateField(sequences[i]));
                    }

                    var conditions = ConditionExpression.And();

                    foreach (var fieldSetter in statement.Updation)
                    {
                        conditions.Add(Expression.Equal(fieldSetter.Field, fieldSetter.Value));
                    }

                    if (conditions.Count > 0)
                    {
                        if (statement.HasParameters)
                        {
                            foreach (var parameter in statement.Parameters)
                            {
                                selection.Parameters.Add(parameter);
                            }
                        }

                        selection.Where = conditions;
                        statement.Slaves.Add(selection);
                    }
                }

                if (statement.Fields.Count > 0)
                {
                    yield return(statement);
                }
            }
        }