예제 #1
0
        public bool HasChanged(MappingMemberDescriptor memberDescriptor, object val)
        {
            object oldVal;
            if (!this._fakes.TryGetValue(memberDescriptor.MemberInfo, out oldVal))
            {
                return true;
            }

            if (memberDescriptor.MemberInfoType == UtilConstants.TypeOfByteArray)
            {
                //byte[] is a big big hole~
                return !AreEqual((byte[])oldVal, (byte[])val);
            }

            return !Utils.AreEqual(oldVal, val);
        }
예제 #2
0
        public virtual int Update <TEntity>(TEntity entity, string table)
        {
            Utils.CheckNull(entity);

            TypeDescriptor typeDescriptor = TypeDescriptor.GetDescriptor(entity.GetType());

            EnsureEntityHasPrimaryKey(typeDescriptor);

            MappingMemberDescriptor keyMemberDescriptor = typeDescriptor.PrimaryKey;
            MemberInfo keyMember = keyMemberDescriptor.MemberInfo;

            object keyVal = null;

            IEntityState entityState = this.TryGetTrackedEntityState(entity);
            Dictionary <MappingMemberDescriptor, DbExpression> updateColumns = new Dictionary <MappingMemberDescriptor, DbExpression>();

            foreach (var kv in typeDescriptor.MappingMemberDescriptors)
            {
                MemberInfo member = kv.Key;
                MappingMemberDescriptor memberDescriptor = kv.Value;

                if (member == keyMember)
                {
                    keyVal = memberDescriptor.GetValue(entity);
                    keyMemberDescriptor = memberDescriptor;
                    continue;
                }

                if (memberDescriptor.IsAutoIncrement)
                {
                    continue;
                }

                object val = memberDescriptor.GetValue(entity);

                if (entityState != null && !entityState.HasChanged(memberDescriptor, val))
                {
                    continue;
                }

                DbExpression valExp = DbExpression.Parameter(val, memberDescriptor.MemberInfoType);
                updateColumns.Add(memberDescriptor, valExp);
            }

            if (keyVal == null)
            {
                throw new ChloeException(string.Format("The primary key '{0}' could not be null.", keyMember.Name));
            }

            if (updateColumns.Count == 0)
            {
                return(0);
            }

            DbTable      dbTable      = table == null ? typeDescriptor.Table : new DbTable(table, typeDescriptor.Table.Schema);
            DbExpression left         = new DbColumnAccessExpression(dbTable, keyMemberDescriptor.Column);
            DbExpression right        = DbExpression.Parameter(keyVal, keyMemberDescriptor.MemberInfoType);
            DbExpression conditionExp = new DbEqualExpression(left, right);

            DbUpdateExpression e = new DbUpdateExpression(dbTable, conditionExp);

            foreach (var item in updateColumns)
            {
                e.UpdateColumns.Add(item.Key.Column, item.Value);
            }

            int ret = this.ExecuteSqlCommand(e);

            if (entityState != null)
            {
                entityState.Refresh();
            }
            return(ret);
        }
예제 #3
0
        public virtual object Insert <TEntity>(Expression <Func <TEntity> > content, string table)
        {
            Utils.CheckNull(content);

            TypeDescriptor typeDescriptor = TypeDescriptor.GetDescriptor(typeof(TEntity));

            MappingMemberDescriptor keyMemberDescriptor           = typeDescriptor.PrimaryKey;
            MappingMemberDescriptor autoIncrementMemberDescriptor = typeDescriptor.AutoIncrement;

            Dictionary <MemberInfo, Expression> insertColumns = InitMemberExtractor.Extract(content);

            DbTable explicitDbTable = null;

            if (table != null)
            {
                explicitDbTable = new DbTable(table, typeDescriptor.Table.Schema);
            }
            DefaultExpressionParser expressionParser = typeDescriptor.GetExpressionParser(explicitDbTable);
            DbInsertExpression      e = new DbInsertExpression(explicitDbTable ?? typeDescriptor.Table);

            object keyVal = null;

            foreach (var kv in insertColumns)
            {
                MemberInfo key = kv.Key;
                MappingMemberDescriptor memberDescriptor = typeDescriptor.TryGetMappingMemberDescriptor(key);

                if (memberDescriptor == null)
                {
                    throw new ChloeException(string.Format("The member '{0}' does not map any column.", key.Name));
                }

                if (memberDescriptor == autoIncrementMemberDescriptor)
                {
                    throw new ChloeException(string.Format("Could not insert value into the identity column '{0}'.", memberDescriptor.Column.Name));
                }

                if (memberDescriptor.IsPrimaryKey)
                {
                    object val = ExpressionEvaluator.Evaluate(kv.Value);
                    if (val == null)
                    {
                        throw new ChloeException(string.Format("The primary key '{0}' could not be null.", memberDescriptor.MemberInfo.Name));
                    }
                    else
                    {
                        keyVal = val;
                        e.InsertColumns.Add(memberDescriptor.Column, DbExpression.Parameter(keyVal));
                        continue;
                    }
                }

                e.InsertColumns.Add(memberDescriptor.Column, expressionParser.Parse(kv.Value));
            }

            if (keyMemberDescriptor != null)
            {
                //主键为空并且主键又不是自增列
                if (keyVal == null && keyMemberDescriptor != autoIncrementMemberDescriptor)
                {
                    throw new ChloeException(string.Format("The primary key '{0}' could not be null.", keyMemberDescriptor.MemberInfo.Name));
                }
            }

            if (keyMemberDescriptor == null || keyMemberDescriptor != autoIncrementMemberDescriptor)
            {
                this.ExecuteSqlCommand(e);
                return(keyVal); /* It will return null if an entity does not define primary key. */
            }

            IDbExpressionTranslator translator = this.DbContextServiceProvider.CreateDbExpressionTranslator();
            List <DbParam>          parameters;
            string sql = translator.Translate(e, out parameters);

            sql = string.Concat(sql, ";", this.GetSelectLastInsertIdClause());

            //SELECT @@IDENTITY 返回的是 decimal 类型
            object retIdentity = this.Session.ExecuteScalar(sql, parameters.ToArray());

            if (retIdentity == null || retIdentity == DBNull.Value)
            {
                throw new ChloeException("Unable to get the identity value.");
            }

            retIdentity = ConvertIdentityType(retIdentity, autoIncrementMemberDescriptor.MemberInfoType);
            return(retIdentity);
        }
예제 #4
0
        public virtual TEntity Insert <TEntity>(TEntity entity, string table)
        {
            Utils.CheckNull(entity);

            TypeDescriptor typeDescriptor = TypeDescriptor.GetDescriptor(entity.GetType());

            MappingMemberDescriptor keyMemberDescriptor = typeDescriptor.PrimaryKey;

            object keyValue = null;

            MappingMemberDescriptor autoIncrementMemberDescriptor = typeDescriptor.AutoIncrement;

            Dictionary <MappingMemberDescriptor, DbExpression> insertColumns = new Dictionary <MappingMemberDescriptor, DbExpression>();

            foreach (var kv in typeDescriptor.MappingMemberDescriptors)
            {
                MappingMemberDescriptor memberDescriptor = kv.Value;

                if (memberDescriptor == autoIncrementMemberDescriptor)
                {
                    continue;
                }

                object val = memberDescriptor.GetValue(entity);

                if (memberDescriptor == keyMemberDescriptor)
                {
                    keyValue = val;
                }

                DbExpression valExp = DbExpression.Parameter(val, memberDescriptor.MemberInfoType);
                insertColumns.Add(memberDescriptor, valExp);
            }

            if (keyMemberDescriptor != null)
            {
                //主键为空并且主键又不是自增列
                if (keyValue == null && keyMemberDescriptor != autoIncrementMemberDescriptor)
                {
                    throw new ChloeException(string.Format("The primary key '{0}' could not be null.", keyMemberDescriptor.MemberInfo.Name));
                }
            }

            DbTable            dbTable = table == null ? typeDescriptor.Table : new DbTable(table, typeDescriptor.Table.Schema);
            DbInsertExpression e       = new DbInsertExpression(dbTable);

            foreach (var kv in insertColumns)
            {
                e.InsertColumns.Add(kv.Key.Column, kv.Value);
            }

            if (autoIncrementMemberDescriptor == null)
            {
                this.ExecuteSqlCommand(e);
                return(entity);
            }

            IDbExpressionTranslator translator = this.DbContextServiceProvider.CreateDbExpressionTranslator();
            List <DbParam>          parameters;
            string sql = translator.Translate(e, out parameters);

            sql = string.Concat(sql, ";", this.GetSelectLastInsertIdClause());

            //SELECT @@IDENTITY 返回的是 decimal 类型
            object retIdentity = this.Session.ExecuteScalar(sql, parameters.ToArray());

            if (retIdentity == null || retIdentity == DBNull.Value)
            {
                throw new ChloeException("Unable to get the identity value.");
            }

            retIdentity = ConvertIdentityType(retIdentity, autoIncrementMemberDescriptor.MemberInfoType);
            autoIncrementMemberDescriptor.SetValue(entity, retIdentity);
            return(entity);
        }
예제 #5
0
        DataTable ToSqlBulkCopyDataTable <TModel>(List <TModel> modelList, TypeDescriptor typeDescriptor)
        {
            DataTable dt = new DataTable();

            List <SysColumn>     columns        = GetTableColumns(typeDescriptor.Table.Name);
            List <ColumnMapping> columnMappings = new List <ColumnMapping>();

            var mappingMemberDescriptors = typeDescriptor.MappingMemberDescriptors.Select(a => a.Value).ToList();

            for (int i = 0; i < columns.Count; i++)
            {
                var column = columns[i];
                MappingMemberDescriptor mappingMemberDescriptor = mappingMemberDescriptors.Where(a => string.Equals(a.Column.Name, column.Name)).FirstOrDefault();
                if (mappingMemberDescriptor == null)
                {
                    mappingMemberDescriptor = mappingMemberDescriptors.Where(a => string.Equals(a.Column.Name, column.Name, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
                }

                ColumnMapping columnMapping = new ColumnMapping(column);
                Type          dataType;
                if (mappingMemberDescriptor == null)
                {
                    /*
                     * 由于 SqlBulkCopy 要求传入的列必须与表列一一对应,因此,如果 model 中没有与列对应的属性,则使用列数据类型的默认值
                     */

                    SysType sysType = GetSysTypeByTypeName(column.TypeName);
                    columnMapping.DefaultValue = column.IsNullable ? null : sysType.DefaultValue;
                    dataType = sysType.CSharpType;
                }
                else
                {
                    columnMapping.MapMember = mappingMemberDescriptor.MemberInfo;
                    dataType = mappingMemberDescriptor.MemberInfoType.GetUnderlyingType();
                    if (dataType.IsEnum)
                    {
                        dataType = Enum.GetUnderlyingType(dataType);
                    }
                }

                columnMappings.Add(columnMapping);
                dt.Columns.Add(new DataColumn(column.Name, dataType));
            }

            foreach (var model in modelList)
            {
                DataRow dr = dt.NewRow();
                for (int i = 0; i < columnMappings.Count; i++)
                {
                    ColumnMapping columnMapping = columnMappings[i];
                    MemberInfo    member        = columnMapping.MapMember;
                    object        value         = null;
                    if (member == null)
                    {
                        value = columnMapping.DefaultValue;
                    }
                    else
                    {
                        value = member.GetMemberValue(model);
                        if (member.GetMemberType().GetUnderlyingType().IsEnum)
                        {
                            if (value != null)
                            {
                                value = Convert.ChangeType(value, Enum.GetUnderlyingType(value.GetType()));
                            }
                        }
                    }

                    dr[i] = value ?? DBNull.Value;
                }

                dt.Rows.Add(dr);
            }

            return(dt);
        }
예제 #6
0
        public override void InsertRange <TEntity>(List <TEntity> entities, bool keepIdentity = false)
        {
            /*
             * 将 entities 分批插入数据库
             * 每批生成 insert into TableName(...) values(...),(...)...
             * 该方法相对循环一条一条插入,速度提升 2/3 这样
             */

            Utils.CheckNull(entities);
            if (entities.Count == 0)
            {
                return;
            }

            int maxParameters = 2100;
            int batchSize     = 50; /* 每批实体大小,此值通过测试得出相对插入速度比较快的一个值 */

            TypeDescriptor typeDescriptor = TypeDescriptor.GetDescriptor(typeof(TEntity));

            var e = typeDescriptor.MappingMemberDescriptors.Select(a => a.Value);

            if (keepIdentity == false)
            {
                e = e.Where(a => a.IsAutoIncrement == false);
            }
            List <MappingMemberDescriptor> mappingMemberDescriptors = e.ToList();
            int maxDbParamsCount = maxParameters - mappingMemberDescriptors.Count; /* 控制一个 sql 的参数个数 */

            string sqlTemplate = AppendInsertRangeSqlTemplate(typeDescriptor, mappingMemberDescriptors);

            Action insertAction = () =>
            {
                int            batchCount = 0;
                List <DbParam> dbParams   = new List <DbParam>();
                StringBuilder  sqlBuilder = new StringBuilder();
                for (int i = 0; i < entities.Count; i++)
                {
                    var entity = entities[i];

                    if (batchCount > 0)
                    {
                        sqlBuilder.Append(",");
                    }

                    sqlBuilder.Append("(");
                    for (int j = 0; j < mappingMemberDescriptors.Count; j++)
                    {
                        if (j > 0)
                        {
                            sqlBuilder.Append(",");
                        }

                        MappingMemberDescriptor mappingMemberDescriptor = mappingMemberDescriptors[j];
                        object val = mappingMemberDescriptor.GetValue(entity);
                        if (val == null)
                        {
                            sqlBuilder.Append("NULL");
                            continue;
                        }

                        Type valType = val.GetType();
                        if (valType.IsEnum)
                        {
                            val     = Convert.ChangeType(val, Enum.GetUnderlyingType(valType));
                            valType = val.GetType();
                        }

                        if (ToStringableNumericTypes.ContainsKey(valType))
                        {
                            sqlBuilder.Append(val.ToString());
                            continue;
                        }

                        if (val is bool)
                        {
                            if ((bool)val == true)
                            {
                                sqlBuilder.AppendFormat("1");
                            }
                            else
                            {
                                sqlBuilder.AppendFormat("0");
                            }
                            continue;
                        }
                        else if (val is double)
                        {
                            double v = (double)val;
                            if (v >= long.MinValue && v <= long.MaxValue)
                            {
                                sqlBuilder.Append(((long)v).ToString());
                                continue;
                            }
                        }
                        else if (val is float)
                        {
                            float v = (float)val;
                            if (v >= long.MinValue && v <= long.MaxValue)
                            {
                                sqlBuilder.Append(((long)v).ToString());
                                continue;
                            }
                        }
                        else if (val is decimal)
                        {
                            decimal v = (decimal)val;
                            if (v >= long.MinValue && v <= long.MaxValue)
                            {
                                sqlBuilder.Append(((long)v).ToString());
                                continue;
                            }
                        }

                        string  paramName = UtilConstants.ParameterNamePrefix + dbParams.Count.ToString();
                        DbParam dbParam   = new DbParam(paramName, val)
                        {
                            DbType = mappingMemberDescriptor.Column.DbType
                        };
                        dbParams.Add(dbParam);
                        sqlBuilder.Append(paramName);
                    }
                    sqlBuilder.Append(")");

                    batchCount++;

                    if ((batchCount >= 20 && dbParams.Count >= 120 /*参数个数太多也会影响速度*/) || dbParams.Count >= maxDbParamsCount || batchCount >= batchSize || (i + 1) == entities.Count)
                    {
                        sqlBuilder.Insert(0, sqlTemplate);
                        string sql = sqlBuilder.ToString();
                        this.Session.ExecuteNonQuery(sql, dbParams.ToArray());

                        sqlBuilder.Clear();
                        dbParams.Clear();
                        batchCount = 0;
                    }
                }
            };

            Action fAction = () =>
            {
                bool   shouldTurnOff_IDENTITY_INSERT = false;
                string tableName = null;
                if (keepIdentity == true)
                {
                    tableName = AppendTableName(typeDescriptor.Table);
                    this.Session.ExecuteNonQuery(string.Format("SET IDENTITY_INSERT {0} ON ", tableName));
                    shouldTurnOff_IDENTITY_INSERT = true;
                }

                insertAction();
                if (shouldTurnOff_IDENTITY_INSERT == true)
                {
                    this.Session.ExecuteNonQuery(string.Format("SET IDENTITY_INSERT {0} OFF ", tableName));
                }
            };

            if (this.Session.IsInTransaction)
            {
                fAction();
            }
            else
            {
                /* 因为分批插入,所以需要开启事务保证数据一致性 */
                this.Session.BeginTransaction();
                try
                {
                    fAction();
                    this.Session.CommitTransaction();
                }
                catch
                {
                    if (this.Session.IsInTransaction)
                    {
                        this.Session.RollbackTransaction();
                    }
                    throw;
                }
            }
        }
예제 #7
0
        public override TEntity Insert <TEntity>(TEntity entity, string table)
        {
            Utils.CheckNull(entity);

            TypeDescriptor typeDescriptor = TypeDescriptor.GetDescriptor(entity.GetType());

            MappingMemberDescriptor keyMemberDescriptor = typeDescriptor.PrimaryKey;
            MemberInfo keyMember = typeDescriptor.PrimaryKey.MemberInfo;

            object keyValue = null;

            string sequenceName;
            object sequenceValue = null;
            MappingMemberDescriptor defineSequenceMemberDescriptor = GetDefineSequenceMemberDescriptor(typeDescriptor, out sequenceName);

            if (defineSequenceMemberDescriptor != null)
            {
                sequenceValue = ConvertIdentityType(this.GetSequenceNextValue(sequenceName), defineSequenceMemberDescriptor.MemberInfoType);
            }

            Dictionary <MappingMemberDescriptor, DbExpression> insertColumns = new Dictionary <MappingMemberDescriptor, DbExpression>();

            foreach (var kv in typeDescriptor.MappingMemberDescriptors)
            {
                MemberInfo member = kv.Key;
                MappingMemberDescriptor memberDescriptor = kv.Value;

                object val = null;
                if (defineSequenceMemberDescriptor != null && memberDescriptor == defineSequenceMemberDescriptor)
                {
                    val = sequenceValue;
                }
                else
                {
                    val = memberDescriptor.GetValue(entity);
                }

                if (memberDescriptor == keyMemberDescriptor)
                {
                    keyValue = val;
                }

                DbExpression valExp = DbExpression.Parameter(val, memberDescriptor.MemberInfoType);
                insertColumns.Add(memberDescriptor, valExp);
            }

            if (keyMemberDescriptor != null && keyValue == null)
            {
                throw new ChloeException(string.Format("The primary key '{0}' could not be null.", keyMemberDescriptor.MemberInfo.Name));
            }

            DbTable            dbTable = table == null ? typeDescriptor.Table : new DbTable(table, typeDescriptor.Table.Schema);
            DbInsertExpression e       = new DbInsertExpression(dbTable);

            foreach (var kv in insertColumns)
            {
                e.InsertColumns.Add(kv.Key.Column, kv.Value);
            }

            this.ExecuteSqlCommand(e);

            if (defineSequenceMemberDescriptor != null)
            {
                defineSequenceMemberDescriptor.SetValue(entity, sequenceValue);
            }

            return(entity);
        }
예제 #8
0
        static Expression <Func <TEntity, bool> > BuildPredicate <TEntity>(object key)
        {
            /*
             * key:
             * 如果实体是单一主键,则传入的 key 与主键属性类型相同的值
             * 如果实体是多主键,则传入的 key 须是包含了与实体主键类型相同的属性的对象,如:new { Key1 = "1", Key2 = "2" }
             */

            Utils.CheckNull(key);

            Type           entityType     = typeof(TEntity);
            TypeDescriptor typeDescriptor = TypeDescriptor.GetDescriptor(entityType);

            EnsureEntityHasPrimaryKey(typeDescriptor);

            KeyValuePairList <MemberInfo, object> keyValueMap = new KeyValuePairList <MemberInfo, object>();

            if (typeDescriptor.PrimaryKeys.Count == 1)
            {
                keyValueMap.Add(typeDescriptor.PrimaryKeys[0].MemberInfo, key);
            }
            else
            {
                /*
                 * key: new { Key1 = "1", Key2 = "2" }
                 */

                object multipleKeyObject     = key;
                Type   multipleKeyObjectType = multipleKeyObject.GetType();

                for (int i = 0; i < typeDescriptor.PrimaryKeys.Count; i++)
                {
                    MappingMemberDescriptor keyMemberDescriptor = typeDescriptor.PrimaryKeys[i];
                    MemberInfo keyMember = multipleKeyObjectType.GetProperty(keyMemberDescriptor.MemberInfo.Name);
                    if (keyMember == null)
                    {
                        throw new ArgumentException(string.Format("The input object does not define property for key '{0}'.", keyMemberDescriptor.MemberInfo.Name));
                    }

                    object value = keyMember.GetMemberValue(multipleKeyObject);
                    if (value == null)
                    {
                        throw new ArgumentException(string.Format("The primary key '{0}' could not be null.", keyMemberDescriptor.MemberInfo.Name));
                    }

                    keyValueMap.Add(keyMemberDescriptor.MemberInfo, value);
                }
            }

            ParameterExpression parameter  = Expression.Parameter(entityType, "a");
            Expression          lambdaBody = null;

            foreach (var keyValue in keyValueMap)
            {
                Expression propOrField  = Expression.PropertyOrField(parameter, keyValue.Key.Name);
                Expression wrappedValue = Chloe.Extensions.ExpressionExtension.MakeWrapperAccess(keyValue.Value, keyValue.Key.GetMemberType());
                Expression e            = Expression.Equal(propOrField, wrappedValue);
                lambdaBody = lambdaBody == null ? e : Expression.AndAlso(lambdaBody, e);
            }

            Expression <Func <TEntity, bool> > predicate = Expression.Lambda <Func <TEntity, bool> >(lambdaBody, parameter);

            return(predicate);
        }
예제 #9
0
        public override TEntity Insert <TEntity>(TEntity entity, string table)
        {
            Utils.CheckNull(entity);

            TypeDescriptor typeDescriptor = TypeDescriptor.GetDescriptor(entity.GetType());

            Dictionary <MappingMemberDescriptor, object> keyValueMap = CreateKeyValueMap(typeDescriptor);

            string sequenceName;
            object sequenceValue = null;
            MappingMemberDescriptor defineSequenceMemberDescriptor = GetDefineSequenceMemberDescriptor(typeDescriptor, out sequenceName);

            if (defineSequenceMemberDescriptor != null)
            {
                if (defineSequenceMemberDescriptor.IsPrimaryKey && typeDescriptor.PrimaryKeys.Count > 1)
                {
                    /* 自增列不能作为联合主键成员 */
                    throw new ChloeException("The member of marked sequence can not be union key.");
                }

                sequenceValue = ConvertIdentityType(this.GetSequenceNextValue(sequenceName), defineSequenceMemberDescriptor.MemberInfoType);
            }

            Dictionary <MappingMemberDescriptor, DbExpression> insertColumns = new Dictionary <MappingMemberDescriptor, DbExpression>();

            foreach (var kv in typeDescriptor.MappingMemberDescriptors)
            {
                MemberInfo member = kv.Key;
                MappingMemberDescriptor memberDescriptor = kv.Value;

                object val = null;
                if (defineSequenceMemberDescriptor != null && memberDescriptor == defineSequenceMemberDescriptor)
                {
                    val = sequenceValue;
                }
                else
                {
                    val = memberDescriptor.GetValue(entity);
                }

                if (keyValueMap.ContainsKey(memberDescriptor))
                {
                    keyValueMap[memberDescriptor] = val;
                }

                DbExpression valExp = DbExpression.Parameter(val, memberDescriptor.MemberInfoType);
                insertColumns.Add(memberDescriptor, valExp);
            }

            MappingMemberDescriptor nullValueKey = keyValueMap.Where(a => a.Value == null).Select(a => a.Key).FirstOrDefault();

            if (nullValueKey != null)
            {
                throw new ChloeException(string.Format("The primary key '{0}' could not be null.", nullValueKey.MemberInfo.Name));
            }

            DbTable            dbTable = table == null ? typeDescriptor.Table : new DbTable(table, typeDescriptor.Table.Schema);
            DbInsertExpression e       = new DbInsertExpression(dbTable);

            foreach (var kv in insertColumns)
            {
                e.InsertColumns.Add(kv.Key.Column, kv.Value);
            }

            this.ExecuteSqlCommand(e);

            if (defineSequenceMemberDescriptor != null)
            {
                defineSequenceMemberDescriptor.SetValue(entity, sequenceValue);
            }

            return(entity);
        }
예제 #10
0
        public override int Update <TEntity>(TEntity entity, string table)
        {
            Utils.CheckNull(entity);

            TypeDescriptor typeDescriptor = TypeDescriptor.GetDescriptor(entity.GetType());

            EnsureMappingTypeHasPrimaryKey(typeDescriptor);

            Dictionary <MappingMemberDescriptor, object> keyValueMap = CreateKeyValueMap(typeDescriptor);

            IEntityState entityState = this.TryGetTrackedEntityState(entity);
            Dictionary <MappingMemberDescriptor, DbExpression> updateColumns = new Dictionary <MappingMemberDescriptor, DbExpression>();

            foreach (var kv in typeDescriptor.MappingMemberDescriptors)
            {
                MappingMemberDescriptor memberDescriptor = kv.Value;

                if (keyValueMap.ContainsKey(memberDescriptor))
                {
                    keyValueMap[memberDescriptor] = memberDescriptor.GetValue(entity);
                    continue;
                }

                SequenceAttribute attr = (SequenceAttribute)memberDescriptor.GetCustomAttribute(typeof(SequenceAttribute));
                if (attr != null)
                {
                    continue;
                }

                object val = memberDescriptor.GetValue(entity);

                if (entityState != null && !entityState.HasChanged(memberDescriptor, val))
                {
                    continue;
                }

                DbExpression valExp = DbExpression.Parameter(val, memberDescriptor.MemberInfoType);
                updateColumns.Add(memberDescriptor, valExp);
            }

            if (updateColumns.Count == 0)
            {
                return(0);
            }

            DbTable            dbTable      = table == null ? typeDescriptor.Table : new DbTable(table, typeDescriptor.Table.Schema);
            DbExpression       conditionExp = MakeCondition(keyValueMap, dbTable);
            DbUpdateExpression e            = new DbUpdateExpression(dbTable, conditionExp);

            foreach (var item in updateColumns)
            {
                e.UpdateColumns.Add(item.Key.Column, item.Value);
            }

            int ret = this.ExecuteSqlCommand(e);

            if (entityState != null)
            {
                entityState.Refresh();
            }
            return(ret);
        }
예제 #11
0
        public override void InsertRange <TEntity>(List <TEntity> entities, bool keepIdentity = false)
        {
            /*
             * 将 entities 分批插入数据库
             * 每批生成 insert into TableName(...) select ... from dual union all select ... from dual...
             * 对于 oracle,貌似速度提升不了...- -
             * #期待各码友的优化建议#
             */

            Utils.CheckNull(entities);
            if (entities.Count == 0)
            {
                return;
            }

            int maxParameters = 1000;
            int batchSize     = 40; /* 每批实体大小,此值通过测试得出相对插入速度比较快的一个值 */

            TypeDescriptor typeDescriptor = TypeDescriptor.GetDescriptor(typeof(TEntity));

            var e = typeDescriptor.MappingMemberDescriptors.Select(a => a.Value);

            List <MappingMemberDescriptor> mappingMemberDescriptors = e.ToList();
            int maxDbParamsCount = maxParameters - mappingMemberDescriptors.Count; /* 控制一个 sql 的参数个数 */

            string sqlTemplate = AppendInsertRangeSqlTemplate(typeDescriptor, mappingMemberDescriptors, keepIdentity);

            Action insertAction = () =>
            {
                int            batchCount = 0;
                List <DbParam> dbParams   = new List <DbParam>();
                StringBuilder  sqlBuilder = new StringBuilder();
                for (int i = 0; i < entities.Count; i++)
                {
                    var entity = entities[i];

                    if (batchCount > 0)
                    {
                        sqlBuilder.Append(" UNION ALL ");
                    }

                    sqlBuilder.Append(" SELECT ");
                    for (int j = 0; j < mappingMemberDescriptors.Count; j++)
                    {
                        if (j > 0)
                        {
                            sqlBuilder.Append(",");
                        }

                        MappingMemberDescriptor mappingMemberDescriptor = mappingMemberDescriptors[j];

                        string sequenceName;
                        if (keepIdentity == false && HasSequenceAttribute(mappingMemberDescriptor, out sequenceName))
                        {
                            sqlBuilder.AppendFormat("1");
                            continue;
                        }

                        object val = mappingMemberDescriptor.GetValue(entity);
                        if (val == null)
                        {
                            sqlBuilder.Append("NULL");
                            sqlBuilder.Append(" C").Append(j.ToString());
                            continue;
                        }

                        Type valType = val.GetType();
                        if (valType.IsEnum)
                        {
                            val     = Convert.ChangeType(val, Enum.GetUnderlyingType(valType));
                            valType = val.GetType();
                        }

                        if (ToStringableNumericTypes.ContainsKey(valType))
                        {
                            sqlBuilder.Append(val.ToString());
                        }
                        else if (val is bool)
                        {
                            if ((bool)val == true)
                            {
                                sqlBuilder.AppendFormat("1");
                            }
                            else
                            {
                                sqlBuilder.AppendFormat("0");
                            }
                        }
                        else if (val is double)
                        {
                            double v = (double)val;
                            if (v >= long.MinValue && v <= long.MaxValue)
                            {
                                sqlBuilder.Append(((long)v).ToString());
                            }
                        }
                        else if (val is float)
                        {
                            float v = (float)val;
                            if (v >= long.MinValue && v <= long.MaxValue)
                            {
                                sqlBuilder.Append(((long)v).ToString());
                            }
                        }
                        else if (val is decimal)
                        {
                            decimal v = (decimal)val;
                            if (v >= long.MinValue && v <= long.MaxValue)
                            {
                                sqlBuilder.Append(((long)v).ToString());
                            }
                        }
                        else
                        {
                            string  paramName = UtilConstants.ParameterNamePrefix + dbParams.Count.ToString();
                            DbParam dbParam   = new DbParam(paramName, val)
                            {
                                DbType = mappingMemberDescriptor.Column.DbType
                            };
                            dbParams.Add(dbParam);
                            sqlBuilder.Append(paramName);
                        }

                        sqlBuilder.Append(" C").Append(j.ToString());
                    }

                    sqlBuilder.Append(" FROM DUAL");

                    batchCount++;

                    if ((batchCount >= 20 && dbParams.Count >= 400 /*参数个数太多也会影响速度*/) || dbParams.Count >= maxDbParamsCount || batchCount >= batchSize || (i + 1) == entities.Count)
                    {
                        sqlBuilder.Insert(0, sqlTemplate);

                        if (keepIdentity == false)
                        {
                            sqlBuilder.Append(") T");
                        }

                        string sql = sqlBuilder.ToString();
                        this.Session.ExecuteNonQuery(sql, dbParams.ToArray());

                        sqlBuilder.Clear();
                        dbParams.Clear();
                        batchCount = 0;
                    }
                }
            };

            Action fAction = insertAction;

            if (this.Session.IsInTransaction)
            {
                fAction();
            }
            else
            {
                /* 因为分批插入,所以需要开启事务保证数据一致性 */
                this.Session.BeginTransaction();
                try
                {
                    fAction();
                    this.Session.CommitTransaction();
                }
                catch
                {
                    if (this.Session.IsInTransaction)
                    {
                        this.Session.RollbackTransaction();
                    }
                    throw;
                }
            }
        }
예제 #12
0
        public override T Insert <T>(T entity)
        {
            Utils.CheckNull(entity);

            TypeDescriptor typeDescriptor = TypeDescriptor.GetDescriptor(entity.GetType());

            EnsureMappingTypeHasPrimaryKey(typeDescriptor);

            MappingMemberDescriptor keyMemberDescriptor = typeDescriptor.PrimaryKey;
            var keyMember = typeDescriptor.PrimaryKey.MemberInfo;

            object keyValue = null;

            MappingMemberDescriptor autoIncrementMemberDescriptor = GetAutoIncrementMemberDescriptor(typeDescriptor);

            Dictionary <MappingMemberDescriptor, DbExpression> insertColumns = new Dictionary <MappingMemberDescriptor, DbExpression>();

            foreach (var kv in typeDescriptor.MappingMemberDescriptors)
            {
                var member           = kv.Key;
                var memberDescriptor = kv.Value;

                if (memberDescriptor == autoIncrementMemberDescriptor)
                {
                    continue;
                }

                var val = memberDescriptor.GetValue(entity);

                if (memberDescriptor == keyMemberDescriptor)
                {
                    keyValue = val;
                }

                DbExpression valExp = DbExpression.Parameter(val, memberDescriptor.MemberInfoType);
                insertColumns.Add(memberDescriptor, valExp);
            }

            //主键为空并且主键又不是自增列
            if (keyValue == null && keyMemberDescriptor != autoIncrementMemberDescriptor)
            {
                throw new Exception(string.Format("主键 {0} 值为 null", keyMemberDescriptor.MemberInfo.Name));
            }

            DbInsertExpression e = new DbInsertExpression(typeDescriptor.Table);

            foreach (var kv in insertColumns)
            {
                e.InsertColumns.Add(kv.Key.Column, kv.Value);
            }

            if (autoIncrementMemberDescriptor == null)
            {
                this.ExecuteSqlCommand(e);
                return(entity);
            }

            IDbExpressionTranslator translator = this.DbContextServiceProvider.CreateDbExpressionTranslator();
            List <DbParam>          parameters;
            string sql = translator.Translate(e, out parameters);

            sql += ";SELECT @@IDENTITY";

            //SELECT @@IDENTITY 返回的是 decimal 类型
            object retIdentity = this.CurrentSession.ExecuteScalar(sql, parameters.ToArray());

            if (retIdentity == null || retIdentity == DBNull.Value)
            {
                throw new Exception("无法获取自增标识");
            }

            retIdentity = ConvertIdentityType(retIdentity, autoIncrementMemberDescriptor.MemberInfoType);
            autoIncrementMemberDescriptor.SetValue(entity, retIdentity);
            return(entity);
        }
예제 #13
0
        public override int Update <T>(T entity)
        {
            Utils.CheckNull(entity);

            TypeDescriptor typeDescriptor = TypeDescriptor.GetDescriptor(entity.GetType());

            EnsureMappingTypeHasPrimaryKey(typeDescriptor);

            object keyVal = null;
            MappingMemberDescriptor keyMemberDescriptor = typeDescriptor.PrimaryKey;
            MemberInfo keyMember = keyMemberDescriptor.MemberInfo;

            IEntityState entityState = this.TryGetTrackedEntityState(entity);
            Dictionary <MappingMemberDescriptor, DbExpression> updateColumns = new Dictionary <MappingMemberDescriptor, DbExpression>();

            foreach (var kv in typeDescriptor.MappingMemberDescriptors)
            {
                var member           = kv.Key;
                var memberDescriptor = kv.Value;

                if (member == keyMember)
                {
                    keyVal = memberDescriptor.GetValue(entity);
                    keyMemberDescriptor = memberDescriptor;
                    continue;
                }

                AutoIncrementAttribute attr = (AutoIncrementAttribute)memberDescriptor.GetCustomAttribute(typeof(AutoIncrementAttribute));
                if (attr != null)
                {
                    continue;
                }

                var val = memberDescriptor.GetValue(entity);

                if (entityState != null && !entityState.IsChanged(member, val))
                {
                    continue;
                }

                DbExpression valExp = DbExpression.Parameter(val, memberDescriptor.MemberInfoType);
                updateColumns.Add(memberDescriptor, valExp);
            }

            if (keyVal == null)
            {
                throw new Exception(string.Format("实体主键 {0} 值为 null", keyMember.Name));
            }

            if (updateColumns.Count == 0)
            {
                return(0);
            }

            DbExpression left         = new DbColumnAccessExpression(typeDescriptor.Table, keyMemberDescriptor.Column);
            DbExpression right        = DbExpression.Parameter(keyVal, keyMemberDescriptor.MemberInfoType);
            DbExpression conditionExp = new DbEqualExpression(left, right);

            DbUpdateExpression e = new DbUpdateExpression(typeDescriptor.Table, conditionExp);

            foreach (var item in updateColumns)
            {
                e.UpdateColumns.Add(item.Key.Column, item.Value);
            }

            int ret = this.ExecuteSqlCommand(e);

            if (entityState != null)
            {
                entityState.Refresh();
            }
            return(ret);
        }
예제 #14
0
        public override object Insert <T>(Expression <Func <T> > body)
        {
            Utils.CheckNull(body);

            TypeDescriptor typeDescriptor = TypeDescriptor.GetDescriptor(typeof(T));

            EnsureMappingTypeHasPrimaryKey(typeDescriptor);

            MappingMemberDescriptor keyMemberDescriptor           = typeDescriptor.PrimaryKey;
            MappingMemberDescriptor autoIncrementMemberDescriptor = GetAutoIncrementMemberDescriptor(typeDescriptor);

            Dictionary <MemberInfo, Expression> insertColumns = InitMemberExtractor.Extract(body);

            DbInsertExpression e = new DbInsertExpression(typeDescriptor.Table);

            object keyVal = null;

            foreach (var kv in insertColumns)
            {
                MemberInfo key = kv.Key;
                MappingMemberDescriptor memberDescriptor = typeDescriptor.TryGetMappingMemberDescriptor(key);

                if (memberDescriptor == null)
                {
                    throw new Exception(string.Format("成员 {0} 未映射任何列", key.Name));
                }

                if (memberDescriptor == autoIncrementMemberDescriptor)
                {
                    throw new Exception(string.Format("不能将值插入自增长列 '{0}'", memberDescriptor.Column.Name));
                }

                if (memberDescriptor.IsPrimaryKey)
                {
                    object val = ExpressionEvaluator.Evaluate(kv.Value);
                    if (val == null)
                    {
                        throw new Exception(string.Format("主键 {0} 值为 null", memberDescriptor.MemberInfo.Name));
                    }
                    else
                    {
                        keyVal = val;
                        e.InsertColumns.Add(memberDescriptor.Column, DbExpression.Parameter(keyVal));
                        continue;
                    }
                }

                e.InsertColumns.Add(memberDescriptor.Column, typeDescriptor.Visitor.Visit(kv.Value));
            }

            //主键为空并且主键又不是自增列
            if (keyVal == null && keyMemberDescriptor != autoIncrementMemberDescriptor)
            {
                throw new Exception(string.Format("主键 {0} 值为 null", keyMemberDescriptor.MemberInfo.Name));
            }

            if (autoIncrementMemberDescriptor == null)
            {
                this.ExecuteSqlCommand(e);
                return(keyVal);
            }

            IDbExpressionTranslator translator = this.DbContextServiceProvider.CreateDbExpressionTranslator();
            List <DbParam>          parameters;
            string sql = translator.Translate(e, out parameters);

            sql += ";SELECT @@IDENTITY";

            //SELECT @@IDENTITY 返回的是 decimal 类型
            object retIdentity = this.CurrentSession.ExecuteScalar(sql, parameters.ToArray());

            if (retIdentity == null || retIdentity == DBNull.Value)
            {
                throw new Exception("无法获取自增标识");
            }

            retIdentity = ConvertIdentityType(retIdentity, autoIncrementMemberDescriptor.MemberInfoType);
            return(retIdentity);
        }
예제 #15
0
        public override object Insert <TEntity>(Expression <Func <TEntity> > content, string table)
        {
            Utils.CheckNull(content);

            TypeDescriptor typeDescriptor = TypeDescriptor.GetDescriptor(typeof(TEntity));

            if (typeDescriptor.PrimaryKeys.Count > 1)
            {
                /* 对于多主键的实体,暂时不支持调用这个方法进行插入 */
                throw new NotSupportedException(string.Format("Can not call this method because entity '{0}' has multiple keys.", typeDescriptor.EntityType.FullName));
            }

            MappingMemberDescriptor keyMemberDescriptor = typeDescriptor.PrimaryKeys.FirstOrDefault();

            string sequenceName;
            object sequenceValue = null;
            MappingMemberDescriptor defineSequenceMemberDescriptor = GetDefineSequenceMemberDescriptor(typeDescriptor, out sequenceName);

            Dictionary <MemberInfo, Expression> insertColumns = InitMemberExtractor.Extract(content);

            DbTable explicitDbTable = null;

            if (table != null)
            {
                explicitDbTable = new DbTable(table, typeDescriptor.Table.Schema);
            }
            DefaultExpressionParser expressionParser = typeDescriptor.GetExpressionParser(explicitDbTable);
            DbInsertExpression      e = new DbInsertExpression(explicitDbTable ?? typeDescriptor.Table);

            object keyVal = null;

            foreach (var kv in insertColumns)
            {
                MemberInfo key = kv.Key;
                MappingMemberDescriptor memberDescriptor = typeDescriptor.TryGetMappingMemberDescriptor(key);

                if (memberDescriptor == null)
                {
                    throw new ChloeException(string.Format("The member '{0}' does not map any column.", key.Name));
                }

                if (memberDescriptor == defineSequenceMemberDescriptor)
                {
                    throw new ChloeException(string.Format("Can not insert value into the column '{0}', because it's mapping member has define a sequence.", memberDescriptor.Column.Name));
                }

                if (memberDescriptor.IsPrimaryKey)
                {
                    object val = ExpressionEvaluator.Evaluate(kv.Value);
                    if (val == null)
                    {
                        throw new ChloeException(string.Format("The primary key '{0}' could not be null.", memberDescriptor.MemberInfo.Name));
                    }
                    else
                    {
                        keyVal = val;
                        e.InsertColumns.Add(memberDescriptor.Column, DbExpression.Parameter(keyVal));
                        continue;
                    }
                }

                e.InsertColumns.Add(memberDescriptor.Column, expressionParser.Parse(kv.Value));
            }

            if (keyMemberDescriptor == defineSequenceMemberDescriptor)
            {
                sequenceValue = ConvertIdentityType(this.GetSequenceNextValue(sequenceName), defineSequenceMemberDescriptor.MemberInfoType);

                keyVal = sequenceValue;
                e.InsertColumns.Add(keyMemberDescriptor.Column, DbExpression.Parameter(keyVal));
            }

            if (keyMemberDescriptor != null && keyVal == null)
            {
                throw new ChloeException(string.Format("The primary key '{0}' could not be null.", keyMemberDescriptor.MemberInfo.Name));
            }

            this.ExecuteSqlCommand(e);
            return(keyVal); /* It will return null if an entity does not define primary key. */
        }
예제 #16
0
        static Expression <Func <TEntity, bool> > BuildCondition <TEntity>(object key)
        {
            /*
             * key:
             * 如果实体是单一主键,可以传入的 key 与主键属性类型相同的值,亦可以传一个包含了与实体主键类型相同的属性的对象,如:new { Id = 1 }
             * 如果实体是多主键,则传入的 key 须是包含了与实体主键类型相同的属性的对象,如:new { Key1 = "1", Key2 = "2" }
             */

            Utils.CheckNull(key);

            Type           entityType     = typeof(TEntity);
            TypeDescriptor typeDescriptor = TypeDescriptor.GetDescriptor(entityType);

            EnsureEntityHasPrimaryKey(typeDescriptor);

            ParameterExpression parameter     = Expression.Parameter(entityType, "a");
            Expression          conditionBody = null;

            Type keyType = key.GetType();

            if (typeDescriptor.PrimaryKeys.Count == 1 && MappingTypeSystem.IsMappingType(keyType))
            {
                /* a => a.Key == key */

                MappingMemberDescriptor keyDescriptor = typeDescriptor.PrimaryKeys[0];
                Expression propOrField  = Expression.PropertyOrField(parameter, keyDescriptor.MemberInfo.Name);
                Expression wrappedValue = ExpressionExtension.MakeWrapperAccess(key, keyDescriptor.MemberInfoType);
                conditionBody = Expression.Equal(propOrField, wrappedValue);
            }
            else
            {
                /*
                 * key: new { Key1 = "1", Key2 = "2" }
                 */

                /* a => a.Key1 == key.Key1 && a.Key2 == key.Key2 */

                Type keyObjectType = keyType;
                ConstantExpression keyConstantExp = Expression.Constant(key);
                if (keyObjectType == entityType)
                {
                    foreach (MappingMemberDescriptor primaryKey in typeDescriptor.PrimaryKeys)
                    {
                        Expression propOrField = Expression.PropertyOrField(parameter, primaryKey.MemberInfo.Name);
                        Expression keyValue    = Expression.MakeMemberAccess(keyConstantExp, primaryKey.MemberInfo);
                        Expression e           = Expression.Equal(propOrField, keyValue);
                        conditionBody = conditionBody == null ? e : Expression.AndAlso(conditionBody, e);
                    }
                }
                else
                {
                    for (int i = 0; i < typeDescriptor.PrimaryKeys.Count; i++)
                    {
                        MappingMemberDescriptor keyMemberDescriptor = typeDescriptor.PrimaryKeys[i];
                        MemberInfo keyMember      = keyMemberDescriptor.MemberInfo;
                        MemberInfo inputKeyMember = keyObjectType.GetMember(keyMember.Name).FirstOrDefault();
                        if (inputKeyMember == null)
                        {
                            throw new ArgumentException(string.Format("The input object does not define property for key '{0}'.", keyMember.Name));
                        }

                        Expression propOrField = Expression.PropertyOrField(parameter, keyMember.Name);
                        Expression keyValueExp = Expression.MakeMemberAccess(keyConstantExp, inputKeyMember);

                        Type keyMemberType = keyMember.GetMemberType();
                        if (inputKeyMember.GetMemberType() != keyMemberType)
                        {
                            keyValueExp = Expression.Convert(keyValueExp, keyMemberType);
                        }
                        Expression e = Expression.Equal(propOrField, keyValueExp);
                        conditionBody = conditionBody == null ? e : Expression.AndAlso(conditionBody, e);
                    }
                }
            }

            Expression <Func <TEntity, bool> > condition = Expression.Lambda <Func <TEntity, bool> >(conditionBody, parameter);

            return(condition);
        }
예제 #17
0
        public override object Insert <TEntity>(Expression <Func <TEntity> > body)
        {
            Utils.CheckNull(body);

            TypeDescriptor typeDescriptor = TypeDescriptor.GetDescriptor(typeof(TEntity));

            EnsureMappingTypeHasPrimaryKey(typeDescriptor);

            MappingMemberDescriptor keyMemberDescriptor = typeDescriptor.PrimaryKey;

            string sequenceName;
            object sequenceValue = null;
            MappingMemberDescriptor defineSequenceMemberDescriptor = GetDefineSequenceMemberDescriptor(typeDescriptor, out sequenceName);

            Dictionary <MemberInfo, Expression> insertColumns = InitMemberExtractor.Extract(body);

            DbInsertExpression e = new DbInsertExpression(typeDescriptor.Table);

            object keyVal = null;

            foreach (var kv in insertColumns)
            {
                MemberInfo key = kv.Key;
                MappingMemberDescriptor memberDescriptor = typeDescriptor.TryGetMappingMemberDescriptor(key);

                if (memberDescriptor == null)
                {
                    throw new ChloeException(string.Format("The member '{0}' does not map any column.", key.Name));
                }

                if (memberDescriptor == defineSequenceMemberDescriptor)
                {
                    throw new ChloeException(string.Format("Can not insert value into the column '{0}',because it's mapping member has define a sequence.", memberDescriptor.Column.Name));
                }

                if (memberDescriptor.IsPrimaryKey)
                {
                    object val = ExpressionEvaluator.Evaluate(kv.Value);
                    if (val == null)
                    {
                        throw new ChloeException(string.Format("The primary key '{0}' could not be null.", memberDescriptor.MemberInfo.Name));
                    }
                    else
                    {
                        keyVal = val;
                        e.InsertColumns.Add(memberDescriptor.Column, DbExpression.Parameter(keyVal));
                        continue;
                    }
                }

                e.InsertColumns.Add(memberDescriptor.Column, typeDescriptor.Visitor.Visit(kv.Value));
            }

            if (keyMemberDescriptor == defineSequenceMemberDescriptor)
            {
                sequenceValue = ConvertIdentityType(this.GetSequenceNextValue(sequenceName), defineSequenceMemberDescriptor.MemberInfoType);

                keyVal = sequenceValue;
                e.InsertColumns.Add(keyMemberDescriptor.Column, DbExpression.Parameter(keyVal));
            }

            if (keyVal == null)
            {
                throw new ChloeException(string.Format("The primary key '{0}' could not be null.", keyMemberDescriptor.MemberInfo.Name));
            }

            this.ExecuteSqlCommand(e);
            return(keyVal);
        }