/// <summary> /// 初始化 <see cref="SQLiteUpdateExpressionVisitor"/> 类的新实例 /// </summary> /// <param name="provider">查询语义提供者</param> /// <param name="aliases">表别名集合</param> /// <param name="dbQuery">更新语义</param> /// <param name="alias">指定的表达式别名</param> internal SQLiteUpdateExpressionVisitor(IDbQueryProvider provider, TableAlias aliases, IDbQueryableInfo_Update dbQuery, string alias) : base(provider, aliases, dbQuery.Expression) { _alias = alias; _provider = provider; _dbQuery = dbQuery; _expression = base.Expression; }
/// <summary> /// 创建 UPDATE 命令 /// </summary> /// <param name="dbQuery">查询语义</param> /// <param name="token">解析上下文</param> /// <returns></returns> protected override RawCommand ResolveUpdateCommand <T>(IDbQueryableInfo_Update dbQuery, ResolveToken token) { ISqlBuilder builder = this.CreateSqlBuilder(token); var typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo <T>(); builder.Append("UPDATE "); builder.AppendMember(typeRuntime.TableName, !typeRuntime.IsTemporary); builder.Append(" SET"); builder.AppendNewLine(); if (dbQuery.Entity != null) { object entity = dbQuery.Entity; ISqlBuilder seg_Where = this.CreateSqlBuilder(token); bool useKey = false; int length = 0; foreach (var m in typeRuntime.Members) { var column = m.Column; if (column != null && column.IsIdentity) { goto gotoLabel; // Fix issue# 自增列同时又是主键 } if (column != null && column.NoMapped) { continue; } if (m.Column != null && column.DbType is SqlDbType && (SqlDbType)column.DbType == SqlDbType.Timestamp) { continue; // 行版本号 } if (m.ForeignKey != null) { continue; } if (m.Member.MemberType == System.Reflection.MemberTypes.Method) { continue; } builder.AppendMember(m.Member.Name); builder.Append(" = "); gotoLabel: var value = m.Invoke(entity); var seg = this.DbValue.GetSqlValueWidthDefault(value, token, column); if (column == null || !column.IsIdentity) { builder.Append(seg); length = builder.Length; builder.Append(','); builder.AppendNewLine(); } if (column != null && column.IsKey) { useKey = true; seg_Where.AppendMember(m.Member.Name); seg_Where.Append(" = "); seg_Where.Append(seg); seg_Where.Append(" AND "); } } if (!useKey) { throw new XFrameworkException("Update<T>(T value) require entity must have key column."); } builder.Length = length; seg_Where.Length -= 5; builder.AppendNewLine(); builder.Append("WHERE "); builder.Append(seg_Where); } else if (dbQuery.Expression != null) { // SELECT 表达式 LambdaExpression lambda = dbQuery.Expression as LambdaExpression; var body = lambda.Body; Expression expression = null; if (body.NodeType == ExpressionType.MemberInit) { var memberInit = body as MemberInitExpression; var bindings = new List <MemberBinding>(memberInit.Bindings); foreach (var m in typeRuntime.KeyMembers) { var member = Expression.MakeMemberAccess(lambda.Parameters[0], m.Member); var binding = Expression.Bind(m.Member, member); if (!bindings.Any(x => x.Member == m.Member)) { bindings.Add(binding); } } expression = Expression.MemberInit(memberInit.NewExpression, bindings); } else if (body.NodeType == ExpressionType.New) { var newExpression = body as NewExpression; var bindings = new List <MemberBinding>(); for (int i = 0; i < newExpression.Members.Count; i++) { var m = typeRuntime.GetMember(newExpression.Members[i].Name); var binding = Expression.Bind(m.Member, newExpression.Arguments[i].Type != m.DataType ? Expression.Convert(newExpression.Arguments[i], m.DataType) : newExpression.Arguments[i]); bindings.Add(binding); } foreach (var m in typeRuntime.KeyMembers) { var member = Expression.MakeMemberAccess(lambda.Parameters[0], m.Member); var binding = Expression.Bind(m.Member, member); if (!bindings.Any(x => x.Member == m.Member)) { bindings.Add(binding); } } var newExpression2 = Expression.New(typeRuntime.Constructor.Constructor); expression = Expression.MemberInit(newExpression2, bindings); } // 解析查询以确定是否需要嵌套 dbQuery.Query.Select = new DbExpression(DbExpressionType.Select, expression); var cmd = (MappingCommand)this.ResolveSelectCommand(dbQuery.Query, 1, false, null); if ((cmd.NavMembers != null && cmd.NavMembers.Count > 0) || dbQuery.Query.Joins.Count > 0) { if (typeRuntime.KeyMembers == null || typeRuntime.KeyMembers.Count == 0) { throw new XFrameworkException("Update<T>(Expression<Func<T, object>> updateExpression) require entity must have key column."); } // SET 字段 var visitor = new SQLiteUpdateExpressionVisitor(this, null, dbQuery, null); visitor.ParseCommand = this.ResolveSelectCommand; visitor.Write(builder); // WHERE部分 builder.AppendNewLine(); builder.Append("WHERE EXISTS"); visitor.VisitArgument(dbQuery.Query.Select.Expressions[0], true); } else { // 直接 SQL 的 UPDATE 语法 TableAlias aliases = this.PrepareTableAlias(dbQuery.Query, token); var visitor = new SQLiteUpdateExpressionVisitor(this, aliases, dbQuery, null); visitor.ParseCommand = this.ResolveSelectCommand; visitor.Write(builder); var visitor2 = new WhereExpressionVisitor(this, null, dbQuery.Query.Where); visitor2.Write(builder); } } builder.Append(';'); return(new RawCommand(builder.ToString(), builder.Token != null ? builder.Token.Parameters : null, System.Data.CommandType.Text)); }
/// <summary> /// 创建 UPDATE 命令 /// </summary> /// <param name="dbQuery">查询语义</param> /// <param name="token">解析上下文</param> /// <returns></returns> protected override RawCommand ResolveUpdateCommand <T>(IDbQueryableInfo_Update dbQuery, ResolveToken token) { var context = (SqlServerDbContext)token.DbContext; ISqlBuilder builder = this.CreateSqlBuilder(token); var typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo <T>(); builder.Append("UPDATE t0 SET"); builder.AppendNewLine(); if (dbQuery.Entity != null) { object entity = dbQuery.Entity; ISqlBuilder seg_Where = this.CreateSqlBuilder(token); bool useKey = false; int length = 0; foreach (var m in typeRuntime.Members) { var column = m.Column; if (column != null && column.IsIdentity) { goto gotoLabel; // Fix issue# 自增列同时又是主键 } if (column != null && column.NoMapped) { continue; } if (m.Column != null && column.DbType is SqlDbType && (SqlDbType)column.DbType == SqlDbType.Timestamp) { continue; // 行版本号 } if (m.ForeignKey != null) { continue; } if (m.Member.MemberType == System.Reflection.MemberTypes.Method) { continue; } builder.AppendMember("t0", m.Member.Name); builder.Append(" = "); gotoLabel: var value = m.Invoke(entity); var seg = this.DbValue.GetSqlValueWidthDefault(value, token, column); if (column == null || !column.IsIdentity) { builder.Append(seg); length = builder.Length; builder.Append(','); builder.AppendNewLine(); } if (column != null && column.IsKey) { useKey = true; seg_Where.AppendMember("t0", m.Member.Name); seg_Where.Append(" = "); seg_Where.Append(seg); seg_Where.Append(" AND "); } } if (!useKey) { throw new XFrameworkException("Update<T>(T value) require entity must have key column."); } builder.Length = length; seg_Where.Length -= 5; builder.AppendNewLine(); builder.Append("FROM "); builder.AppendMember(typeRuntime.TableName, !typeRuntime.IsTemporary); builder.Append(" t0"); builder.AppendNewLine(); builder.Append("WHERE "); builder.Append(seg_Where); } else if (dbQuery.Expression != null) { TableAlias aliases = this.PrepareTableAlias(dbQuery.Query, token); ExpressionVisitorBase visitor = null; visitor = new UpdateExpressionVisitor(this, aliases, dbQuery.Expression); visitor.Write(builder); builder.AppendNewLine(); builder.Append("FROM "); builder.AppendMember(typeRuntime.TableName, !typeRuntime.IsTemporary); builder.AppendAs("t0"); var cmd = new SqlServerMappingCommand(context, aliases, token) { HasMany = dbQuery.Query.HasMany }; visitor = new SqlServerJoinExpressionVisitor(context, aliases, dbQuery.Query.Joins); visitor.Write(cmd.JoinFragment); visitor = new WhereExpressionVisitor(this, aliases, dbQuery.Query.Where); visitor.Write(cmd.WhereFragment); cmd.AddNavMembers(visitor.NavMembers); builder.Append(cmd.CommandText); } return(new RawCommand(builder.ToString(), builder.Token != null ? builder.Token.Parameters : null, System.Data.CommandType.Text)); }
/// <summary> /// 创建 UPDATE 命令 /// </summary> /// <param name="dbQuery">查询语义</param> /// <param name="token">解析上下文</param> /// <returns></returns> protected override RawCommand ResolveUpdateCommand <T>(IDbQueryableInfo_Update dbQuery, ResolveToken token) { ISqlBuilder builder = this.CreateSqlBuilder(token); var typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo <T>(); builder.Append("UPDATE "); builder.AppendMember(typeRuntime.TableName, !typeRuntime.IsTemporary); builder.Append(" t0 SET"); builder.AppendNewLine(); if (dbQuery.Entity != null) { object entity = dbQuery.Entity; ISqlBuilder seg_Where = this.CreateSqlBuilder(token); bool useKey = false; int length = 0; foreach (var m in typeRuntime.Members) { var column = m.Column; if (column != null && column.IsIdentity) { goto gotoLabel; // Fix issue# 自增列同时又是主键 } if (column != null && column.NoMapped) { continue; } if (m.ForeignKey != null) { continue; } if (m.Member.MemberType == System.Reflection.MemberTypes.Method) { continue; } builder.AppendMember(m.Member.Name); builder.Append(" = "); gotoLabel: if (column == null || !column.IsIdentity) { var value = m.Invoke(entity); var seg = this.DbValue.GetSqlValueWidthDefault(value, token, column); builder.Append(seg); length = builder.Length; builder.Append(','); builder.AppendNewLine(); } if (column != null && column.IsKey) { useKey = true; } } if (!useKey) { throw new XFrameworkException("Update<T>(T value) require T must have key column."); } // ORACLE 需要注意参数顺序问题 int index = -1; foreach (var m in typeRuntime.KeyMembers) { var column = m.Column; var value = m.Invoke(entity); var seg = this.DbValue.GetSqlValueWidthDefault(value, token, column); index += 1; seg_Where.AppendMember(m.Member.Name); seg_Where.Append(" = "); seg_Where.Append(seg); if (index < typeRuntime.KeyMembers.Count - 1) { seg_Where.Append(" AND "); } } builder.Length = length; builder.AppendNewLine(); builder.Append("WHERE "); builder.Append(seg_Where); } else if (dbQuery.Expression != null) { // SELECT 表达式 LambdaExpression lambda = dbQuery.Expression as LambdaExpression; var body = lambda.Body; Expression expression = null; if (body.NodeType == ExpressionType.MemberInit) { var @init = body as MemberInitExpression; var bindings = new List <MemberBinding>(@init.Bindings); foreach (var m in typeRuntime.KeyMembers) { var member = Expression.MakeMemberAccess(lambda.Parameters[0], m.Member); var binding = Expression.Bind(m.Member, member); if (!bindings.Any(x => x.Member == m.Member)) { bindings.Add(binding); } } expression = Expression.MemberInit(@init.NewExpression, bindings); } else if (body.NodeType == ExpressionType.New) { var newExpression = body as NewExpression; var bindings = new List <MemberBinding>(); for (int i = 0; i < newExpression.Members.Count; i++) { var m = typeRuntime.GetMember(newExpression.Members[i].Name); var binding = Expression.Bind(m.Member, newExpression.Arguments[i].Type != m.DataType ? Expression.Convert(newExpression.Arguments[i], m.DataType) : newExpression.Arguments[i]); bindings.Add(binding); } foreach (var m in typeRuntime.KeyMembers) { var member = Expression.MakeMemberAccess(lambda.Parameters[0], m.Member); var binding = Expression.Bind(m.Member, member); if (!bindings.Any(x => x.Member == m.Member)) { bindings.Add(binding); } } var newExpression2 = Expression.New(typeRuntime.Constructor.Constructor); expression = Expression.MemberInit(newExpression2, bindings); } // 解析查询以确定是否需要嵌套 dbQuery.Query.Select = new DbExpression(DbExpressionType.Select, expression); var cmd = (MappingCommand)this.ResolveSelectCommand(dbQuery.Query, 1, false, null);//, token); if ((cmd.NavMembers != null && cmd.NavMembers.Count > 0) || dbQuery.Query.Joins.Count > 0) { // 无法使用 DISTINCT, GROUP BY 等子句从视图中选择 ROWID 或采样。UPDATE 不能用rowid // 有导航属性或者关联查询,使用 MERGE INTO 语法。要求必须有主键 if (typeRuntime.KeyMembers == null || typeRuntime.KeyMembers.Count == 0) { throw new XFrameworkException("Update<T>(Expression<Func<T, object>> updateExpression) require entity must have key column."); } builder.Length = 0; builder.Append("MERGE INTO "); builder.AppendMember(typeRuntime.TableName, !typeRuntime.IsTemporary); builder.AppendNewLine(" t0"); builder.Append("USING ("); cmd = (MappingCommand)this.ResolveSelectCommand(dbQuery.Query, 1, false, token); builder.AppendNewLine(cmd.CommandText); builder.Append(") t1 ON ("); foreach (var m in typeRuntime.KeyMembers) { builder.AppendMember("t0", m.Name); builder.Append(" = "); builder.AppendMember("t1", m.Name); builder.Append(" AND "); } builder.Length -= 5; builder.Append(')'); // UPDATE builder.AppendNewLine(); builder.AppendNewLine("WHEN MATCHED THEN UPDATE SET "); // SET 字段 var visitor = new OracleUpdateExpressionVisitor(this, null, dbQuery.Expression); visitor.Write(builder); } else { // 直接 SQL 的 UPDATE 语法 TableAlias aliases = this.PrepareTableAlias(dbQuery.Query, token); var visitor = new UpdateExpressionVisitor(this, aliases, dbQuery.Expression); visitor.Write(builder); var visitor_ = new WhereExpressionVisitor(this, aliases, dbQuery.Query.Where); visitor_.Write(builder); } } builder.Append(';'); return(new RawCommand(builder.ToString(), builder.Token != null ? builder.Token.Parameters : null, System.Data.CommandType.Text)); }
/// <summary> /// 创建 UPDATE 命令 /// </summary> /// <param name="dbQuery">查询语义</param> /// <param name="token">解析上下文</param> /// <returns></returns> protected abstract RawCommand ResolveUpdateCommand <T>(IDbQueryableInfo_Update dbQuery, ResolveToken token);