Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions doc/版本日志.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,29 @@
# 版本功能更新记录

## v3.1.7.9
## v3.2.0
- 🛠SqlBuilder大量字符串拼接的优化
- 🐞当条件直接写 xxx == null 时,生成的SQL错误的BUG
- 🐞修复批量更新时,更新指定列丢失主键列的BUG,同时更新指定列时,如果有提供指定值,将使用指定值而不是对象的值
- 🐞修改Select时的别名使用,总是使用AS
- 🐞修改Select时的别名使用,总是使用AS(`select *`除外)
- ⚡️更新操作时,SetNull支持多字段设置(使用`new {...}`)
- ⚡️修改接口的签名,将Func<.., object>修改成泛型形式,使用与原来一样,但是在解析表达式时可以带来一些好处
```csharp
IExpUpdate<T> UpdateColumns(Expression<Func<T, object>> columns);
=>
IExpUpdate<T> UpdateColumns<TUpdate>(Expression<Func<T, TUpdate>> columns);

```
- 🐞修复方法解析时遇到的隐式转换`op_Implicit`
- 🐞修复处理Array/Collection的Contains解析

| Provider | 版本要求 |
|---------------------------------|-------|
| `LightORM.Providers.Dameng` | >=0.0.6 |
| `LightORM.Providers.MySql` | >=0.1.4 |
| `LightORM.Providers.Oracle` | >=0.1.5 |
| `LightORM.Providers.PostgreSQL` | >=0.0.9 |
| `LightORM.Providers.Sqlite` | >=0.1.4 |
| `LightORM.Providers.SqlServer` | >=0.1.5 |

## v3.1.7.8
- ⚡️升级`.NET 10`
Expand Down
146 changes: 115 additions & 31 deletions src/LightORM/Builder/DeleteBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@
using System.Text;

namespace LightORM.Builder;

internal record DeleteBuilder<T> : SqlBuilder
{
public new T? TargetObject { get; set; }
public IEnumerable<T> TargetObjects { get; set; } = [];
public T[] TargetObjects { get; set; } = [];
private bool batchDone = false;
public bool IsBatchDelete { get; set; }
public bool ForceDelete { get; set; }
public bool FullDelete { get; set; }
public bool Truncate { get; set; }
HashSet<string> Members { get; set; } = [];
public List<BatchSqlInfo>? BatchInfos { get; set; }
protected override void HandleResult(ICustomDatabase database, ExpressionInfo expInfo, ExpressionResolvedResult result)
{
Expand Down Expand Up @@ -112,6 +114,7 @@ protected override void HandleResult(ICustomDatabase database, ExpressionInfo ex
else
{
Where.Add(result.SqlString!);
Members.AddRange(result.Members);
}
}
}
Expand All @@ -124,22 +127,69 @@ private void CreateBatchDeleteSql(ICustomDatabase database)
ResolveExpressions(database);
var columns = MainTable.TableEntityInfo.Columns
.Where(c => c.IsPrimaryKey || c.IsVersionColumn).ToArray();

BatchInfos = columns.GenBatchInfos(TargetObjects.ToList(), 2000 - DbParameters.Count);
var delete = $"DELETE FROM {GetTableName(database, MainTable, false)}";
if (columns.Length == 0 && Where.Count == 0)
{
throw new LightOrmException("没有主键并且未设置Where条件");
}
BatchInfos = columns.GenBatchInfos(TargetObjects, 2000 - DbParameters.Count);
//var delete = $"DELETE FROM {GetTableName(database, MainTable, false)}";
foreach (var batch in BatchInfos)
{
StringBuilder sb = new();
sb.AppendLine(delete);
List<string> autoWhereList = [];
foreach (var p in batch.Parameters)
StringBuilder sb = new("DELETE FROM ");
//sb.AppendLine(GetTableName(database, MainTable, false));
sb.AppendTableName(database, MainTable, false).AppendLine();
sb.Append("WHERE ");
if (TargetObjects.Length == 0)
{
sb.Append("1=0");
batch.Sql = sb.ToString();
break;
}
sb.Append('(');
for (int rowIndex = 0; rowIndex < batch.Parameters.Count; rowIndex++)
{
var where = string.Join(" AND ", p.Select(c => $"{c.ColumnName} = {c.ParameterName}"));
autoWhereList.Add($"({where})");
List<SimpleColumn>? row = batch.Parameters[rowIndex];
if (columns.Length > 1)
{
sb.Append('(');
for (var i = 0; i < row.Count; i++)
{
if (i > 0)
{
sb.Append(" AND ");
}
sb.AppendEmphasis(row[i].ColumnName, database);
sb.Append(" = ");
sb.WithPrefix(row[i].ParameterName, database);
}
sb.Append(')');
if (rowIndex < batch.Parameters.Count - 1)
sb.Append(" OR ");
}
else
{
if (rowIndex == 0)
{
// 这里直接访问索引0是安全的,因为进入到else分支的话,说明row.Count == 1, 而row.Count是跟前面的columns的数量是一致的
sb.AppendEmphasis(row[0].ColumnName, database);
sb.Append(" IN (");

}
sb.WithPrefix(row[0].ParameterName, database);
if (rowIndex < batch.Parameters.Count - 1)
sb.Append(',');
else
sb.Append(')');
}
}
sb.Append(')');

foreach (var w in Where)
{
sb.AppendLine();
sb.Append("AND ");
sb.Append(w);
}
var autoWhere = string.Join(" OR ", autoWhereList);
Where.Add(autoWhere);
sb.AppendLine($"WHERE {string.Join($"{N}AND ", Where)}");
HandleSqlParameters(sb, database);
batch.Sql = sb.ToString();
}
Expand All @@ -150,10 +200,12 @@ public override string ToSqlString(ICustomDatabase database)
if (IsBatchDelete)
{
CreateBatchDeleteSql(database);
return string.Join(",", BatchInfos?.Select(b => b.Sql) ?? []);
// ToSqlString由内部或者测试项目调用,批量情况下查看SQL使用BatchInfos属性
return string.Empty;
//return string.Join(",", BatchInfos?.Select(b => b.Sql) ?? []);
}
ResolveExpressions(database);
if (ForceDelete)
if (FullDelete)
{
if (Truncate)
{
Expand All @@ -166,30 +218,62 @@ public override string ToSqlString(ICustomDatabase database)
}
else
{
// 没有设置Where条件, 且提供实体值, 则使用主键作为Where条件
if (Where.Count == 0)
if (Where.Count == 0 && TargetObject is null)
{
if (TargetObject is null) LightOrmException.Throw("Where Condition is null and not provider a entity value");
var primary = MainTable.TableEntityInfo.Columns.Where(f => f.IsPrimaryKey).ToArray();
if (primary.Length == 0) LightOrmException.Throw($"Where Condition is null and Model of [{MainTable.Type}] do not has a PrimaryKey");
var wheres = primary.Select(c =>
{
DbParameters.Add(c.ColumnName, c.GetValue(TargetObject!)!);
return $"{database.AttachEmphasis(c.ColumnName)} = {database.AttachPrefix(c.ColumnName)}";
});
Where.AddRange(wheres);
throw new LightOrmException("Where Condition is null and not provider a entity value");
}
StringBuilder sql;
sql = new("DELETE FROM ");
sql.AppendLine(GetTableName(database, MainTable, false));
//sql.AppendLine(GetTableName(database, MainTable, false));
sql.AppendTableName(database, MainTable, false).AppendLine();
// 没有设置Where条件, 且提供实体值, 则使用主键作为Where条件
bool first = true;
if (TargetObject is not null)
{
var keyedColumns = MainTable.TableEntityInfo.Columns.Where(f => f.IsPrimaryKey || f.IsVersionColumn).ToArray();
if (keyedColumns.Length == 0) LightOrmException.Throw($"Where Condition is null and Model of [{MainTable.Type}] do not has a PrimaryKey");
//var wheres = keyedColumns.Select(c =>
//{
// DbParameters.Add(c.ColumnName, c.GetValue(TargetObject!)!);
// return $"{database.AttachEmphasis(c.ColumnName)} = {database.AttachPrefix(c.ColumnName)}";
//});
//Where.AddRange(wheres);
sql.Append("WHERE ");
foreach (var col in keyedColumns)
{
if (Members.Contains(col.PropertyName))
{
continue;
}
DbParameters.Add(col.PropertyName, col.GetValue(TargetObject)!);
if (!first)
{
sql.Append(" AND ");
}
first = false;
sql.Append('(');
sql.AppendEmphasis(col.ColumnName, database);
sql.Append(" = ");
sql.WithPrefix(col.PropertyName, database);
sql.Append(')');
}
}

if (Where.Count > 0)
{
sql.AppendLine($"WHERE {string.Join(" AND ", Where)}");
if (first)
{
sql.Append("WHERE ");
}
else
{
sql.Append(" AND ");
}
//sql.AppendLine($"WHERE {string.Join(" AND ", Where)}");
sql.AppendJoined(Where, " AND ");
}
HandleSqlParameters(sql, database);
return sql.Trim();
}
}


}
82 changes: 54 additions & 28 deletions src/LightORM/Builder/InsertBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace LightORM.Builder;
internal record InsertBuilder<T> : SqlBuilder
{
public new T? TargetObject { get; set; }
public IEnumerable<T> TargetObjects { get; set; } = [];
public T[] TargetObjects { get; set; } = [];
public List<BatchSqlInfo>? BatchInfos { get; set; }
HashSet<string> IgnoreMembers { get; set; } = [];
HashSet<string> Members { get; set; } = [];
Expand Down Expand Up @@ -41,35 +41,58 @@ public void CreateInsertBatchSql(ICustomDatabase database)
.Where(c => !IgnoreMembers.Contains(c.PropertyName))
.Where(c => Members.Contains(c.PropertyName) && !c.IsNotMapped && !c.IsNavigate).ToArray();

BatchInfos = insertColumns.GenBatchInfos(TargetObjects.ToList(), 2000 - DbParameters.Count);
var insert = $"INSERT INTO {GetTableName(database, MainTable, false)} {N}({string.Join(", ", insertColumns.Select(c => database.AttachEmphasis(c.ColumnName)))}) {N}VALUES {N}";
BatchInfos = insertColumns.GenBatchInfos(TargetObjects, 2000 - DbParameters.Count);
//var insert = $"INSERT INTO {GetTableName(database, MainTable, false)} {N}({string.Join(", ", insertColumns.Select(c => database.AttachEmphasis(c.ColumnName)))}) {N}VALUES {N}";
foreach (var item in BatchInfos)
{
StringBuilder sb = new(insert);
List<string> values = [];
StringBuilder sb = CreateInsertBuilder();//new(insert);//
bool firstRow = true;
foreach (var dic in item.Parameters)
{
var rowValues = dic.Select(c =>
{
var val = c.Value;
if (val is null)
{
return "NULL";
}
//if (c.UnderlyingType.IsNumber() || c.UnderlyingType == typeof(string))
//{
// return $"'{val}'";
//}
return database.AttachPrefix(c.ParameterName);
});
values.Add($"({string.Join(", ", rowValues)})");
if (!firstRow)
{
sb.Append(',');
sb.AppendLine();
}
firstRow = false;
sb.Append('(');
foreach (var c in dic)
{
if (c.Value is null)
{
sb.Append("NULL");
}
else
{
sb.WithPrefix(c.ParameterName, database);
}
sb.Append(',');
}
sb.RemoveLast(1);
sb.Append(')');
}
sb.AppendLine($"{string.Join($", {N}", values)}");
HandleSqlParameters(sb, database);
item.Sql = sb.ToString();
}
batchDone = true;

StringBuilder CreateInsertBuilder()
{
var sb = new StringBuilder("INSERT INTO ");
//sb.Append(GetTableName(database, MainTable, false));
sb.AppendTableName(database, MainTable, false).AppendLine();
sb.Append('(');
foreach (var item in insertColumns)
{
sb.AppendEmphasis(item.ColumnName, database);
sb.Append(',');
}
sb.RemoveLast(1);
sb.Append(')');
sb.AppendLine();
sb.AppendLine("VALUES");
return sb;
}
}


Expand All @@ -78,7 +101,9 @@ public override string ToSqlString(ICustomDatabase database)
if (IsBatchInsert)
{
CreateInsertBatchSql(database);
return string.Join(",", BatchInfos?.Select(b => b.Sql) ?? []);
//return string.Join(",", BatchInfos?.Select(b => b.Sql) ?? []);
// ToSqlString由内部或者测试项目调用,批量情况下查看SQL使用BatchInfos属性
return string.Empty;
}

if (TargetObject == null) LightOrmException.Throw("insert null entity");
Expand Down Expand Up @@ -116,8 +141,8 @@ public override string ToSqlString(ICustomDatabase database)
}
foreach (var item in insertColumns)
{
columns.Append(database.AttachEmphasis(item.ColumnName));
columns.Append(", ");
columns.AppendEmphasis(item.ColumnName, database);
columns.Append(',');
var val = item.GetValue(TargetObject!);
if (val is bool b)
{
Expand All @@ -127,14 +152,15 @@ public override string ToSqlString(ICustomDatabase database)
else
{
DbParameters.Add(item.PropertyName, val!);
values.Append(database.AttachPrefix(item.PropertyName));
values.WithPrefix(item.PropertyName, database);
}
values.Append(", ");
values.Append(',');
}
columns.RemoveLast(2);
values.RemoveLast(2);
columns.RemoveLast(1);
values.RemoveLast(1);
StringBuilder sb = new("INSERT INTO");
sb.AppendLine($" {GetTableName(database, MainTable, false)} ");
//sb.AppendLine($" {GetTableName(database, MainTable, false)} ");
sb.AppendTableName(database, MainTable, false).AppendLine();
sb.Append('(');
sb.Append(columns);
sb.AppendLine(")");
Expand Down
Loading
Loading