Skip to content

Commit 36c8a45

Browse files
committed
- 增加 IInsertOrUpdate.UpdateSet 指定更新;
1 parent a76f790 commit 36c8a45

File tree

27 files changed

+369
-85
lines changed

27 files changed

+369
-85
lines changed

Examples/base_entity/Program.cs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -566,14 +566,14 @@ static void Main(string[] args)
566566

567567
.UseConnectionString(FreeSql.DataType.MySql, "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=cccddd;Charset=utf8;SslMode=none;min pool size=1;Max pool size=2;AllowLoadLocalInfile=true")
568568

569-
.UseConnectionString(FreeSql.DataType.SqlServer, "Data Source=.;Integrated Security=True;Initial Catalog=freesqlTest;Pooling=true;Max Pool Size=3;TrustServerCertificate=true")
569+
//.UseConnectionString(FreeSql.DataType.SqlServer, "Data Source=.;Integrated Security=True;Initial Catalog=freesqlTest;Pooling=true;Max Pool Size=3;TrustServerCertificate=true")
570570

571-
//.UseConnectionString(FreeSql.DataType.PostgreSQL, "Host=192.168.164.10;Port=5432;Username=postgres;Password=123456;Database=tedb;Pooling=true;Maximum Pool Size=2")
571+
.UseConnectionString(FreeSql.DataType.PostgreSQL, "Host=192.168.164.10;Port=5432;Username=postgres;Password=123456;Database=tedb;Pooling=true;Maximum Pool Size=2")
572572
//.UseConnectionString(FreeSql.DataType.PostgreSQL, "Host=192.168.164.10;Port=5432;Username=postgres;Password=123456;Database=toc;Pooling=true;Maximum Pool Size=2")
573-
//.UseNameConvert(FreeSql.Internal.NameConvertType.ToLower)
573+
.UseNameConvert(FreeSql.Internal.NameConvertType.ToLower)
574574

575-
.UseConnectionString(FreeSql.DataType.Oracle, "user id=user1;password=123456;data source=//127.0.0.1:1521/XE;Pooling=true;Max Pool Size=2")
576-
.UseNameConvert(FreeSql.Internal.NameConvertType.ToUpper)
575+
//.UseConnectionString(FreeSql.DataType.Oracle, "user id=user1;password=123456;data source=//127.0.0.1:1521/XE;Pooling=true;Max Pool Size=2")
576+
//.UseNameConvert(FreeSql.Internal.NameConvertType.ToUpper)
577577

578578
//.UseConnectionString(FreeSql.DataType.Dameng, "server=127.0.0.1;port=5236;user id=2user;password=123456789;database=2user;poolsize=5;min pool size=1")
579579
//.UseNameConvert(FreeSql.Internal.NameConvertType.ToUpper)
@@ -601,6 +601,12 @@ static void Main(string[] args)
601601
BaseEntity.Initialization(fsql, () => _asyncUow.Value);
602602
#endregion
603603

604+
var iouSetSql01 = fsql.InsertOrUpdate<User1>()
605+
.SetSource(Enumerable.Range(0, 5).Select(a => new User1 { Id = Guid.NewGuid(), Nickname = $"nickname{a}", Username = $"username{a}", Description = $"desc{a}" }).ToArray())
606+
.UpdateSet((a, b) => a.Sort == b.Sort + 10)
607+
.UpdateSet((a, b) => a.Nickname == "xxx")
608+
.ToSql();
609+
604610
var sqlastable1 = fsql.Select<CurrentDetail>(101).AsTable((t, o) => "current_detail_230501").ToSql();
605611
var sqlastable2 = fsql.Update<CurrentDetail>(101).AsTable("current_detail_230501").Set(t => t.StatuId, 1).ToSql();
606612
var sqlastable3 = fsql.Delete<CurrentDetail>(101).AsTable("current_detail_230501").ToSql();

FreeSql.DbContext/FreeSql.DbContext.xml

Lines changed: 0 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

FreeSql/FreeSql.xml

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

FreeSql/Interface/Curd/IInsertOrUpdate.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,16 @@ public interface IInsertOrUpdate<T1> where T1 : class
8686
/// <returns></returns>
8787
IInsertOrUpdate<T1> UpdateColumns(string[] columns);
8888

89+
/// <summary>
90+
/// 设置列的联表值,格式:<para></para>
91+
/// UpdateSet((a, b) => a.Clicks == b.xxx)<para></para>
92+
/// UpdateSet((a, b) => a.Clicks == a.Clicks + 1)
93+
/// </summary>
94+
/// <typeparam name="TMember"></typeparam>
95+
/// <param name="exp"></param>
96+
/// <returns></returns>
97+
IInsertOrUpdate<T1> UpdateSet<TMember>(Expression<Func<T1, T1, TMember>> exp);
98+
8999
/// <summary>
90100
/// 设置表名规则,可用于分库/分表,参数1:默认表名;返回值:新表名;
91101
/// </summary>

FreeSql/Internal/CommonProvider/InsertOrUpdateProvider.cs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public abstract partial class InsertOrUpdateProvider
2323
public bool _doNothing = false;
2424
public Dictionary<string, bool> _updateIgnore = new Dictionary<string, bool>(StringComparer.CurrentCultureIgnoreCase);
2525
public Dictionary<string, bool> _auditValueChangedDict = new Dictionary<string, bool>(StringComparer.CurrentCultureIgnoreCase);
26+
public Dictionary<string, string> _updateSetDict = new Dictionary<string, string>();
2627
public TableInfo _table;
2728
public ColumnInfo[] _tempPrimarys;
2829
public Func<string, string> _tableRule;
@@ -87,6 +88,55 @@ public IInsertOrUpdate<T1> UpdateColumns(string[] columns)
8788
return this;
8889
}
8990

91+
public IInsertOrUpdate<T1> UpdateSet<TMember>(Expression<Func<T1, T1, TMember>> exp)
92+
{
93+
var body = exp?.Body;
94+
var nodeType = body?.NodeType;
95+
if (nodeType == ExpressionType.Convert)
96+
{
97+
body = (body as UnaryExpression)?.Operand;
98+
nodeType = body?.NodeType;
99+
}
100+
switch (nodeType)
101+
{
102+
case ExpressionType.Equal:
103+
break;
104+
default:
105+
throw new Exception("格式错了,请使用 .Set((a,b) => a.name == b.xname)");
106+
}
107+
108+
var equalBinaryExp = body as BinaryExpression;
109+
var cols = new List<SelectColumnInfo>();
110+
_commonExpression.ExpressionSelectColumn_MemberAccess(null, null, cols, SelectTableInfoType.From, equalBinaryExp.Left, true, null);
111+
if (cols.Count != 1) return this;
112+
var col = cols[0].Column;
113+
var valueSql = "";
114+
115+
if (equalBinaryExp.Right.IsParameter())
116+
{
117+
var tmpQuery = _orm.Select<T1, T1>();
118+
var tmpQueryProvider = tmpQuery as Select0Provider;
119+
tmpQueryProvider._tables[0].Alias = "t1";
120+
tmpQueryProvider._tables[0].Parameter = exp.Parameters[0];
121+
tmpQueryProvider._tables[1].Alias = "t2";
122+
tmpQueryProvider._tables[1].Parameter = exp.Parameters[1];
123+
var valueExp = Expression.Lambda<Func<T1, T1, object>>(Expression.Convert(equalBinaryExp.Right, typeof(object)), exp.Parameters);
124+
tmpQuery.GroupBy(valueExp);
125+
valueSql = tmpQueryProvider._groupby?.Remove(0, " \r\nGROUP BY ".Length);
126+
}
127+
else
128+
{
129+
valueSql = _commonExpression.ExpressionLambdaToSql(equalBinaryExp.Right, new CommonExpression.ExpTSC
130+
{
131+
isQuoteName = true,
132+
mapType = equalBinaryExp.Right is BinaryExpression ? null : col.Attribute.MapType
133+
});
134+
}
135+
if (string.IsNullOrEmpty(valueSql)) return this;
136+
_updateSetDict[col.Attribute.Name] = valueSql;
137+
return this;
138+
}
139+
90140
public static void AuditDataValue(object sender, IEnumerable<T1> data, IFreeSql orm, TableInfo table, Dictionary<string, bool> changedDict)
91141
{
92142
if (data?.Any() != true) return;

FreeSql/Internal/CommonProvider/UpdateProvider.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -894,7 +894,9 @@ protected string WhereCaseSource(string CsName, Func<string, string> thenValue)
894894
var sb = new StringBuilder();
895895
sb.Append(_commonUtils.QuoteSqlName(col.Attribute.Name)).Append(" = ");
896896

897-
var valsameIf = col.Attribute.MapType.IsNumberType() || col.Attribute.MapType == typeof(string) || col.Attribute.MapType.NullableTypeOrThis().IsEnum;
897+
var valsameIf = col.Attribute.MapType.IsNumberType() ||
898+
new[] { typeof(string), typeof(DateTime), typeof(DateTime?) }.Contains(col.Attribute.MapType) ||
899+
col.Attribute.MapType.NullableTypeOrThis().IsEnum;
898900
var ds = _source.Select(a => col.GetDbValue(a)).ToArray();
899901
if (valsameIf && ds.All(a => object.Equals(a, ds[0])))
900902
{
@@ -1149,7 +1151,9 @@ public virtual void ToSqlExtension110(StringBuilder sb, bool isAsTableSplited)
11491151
sb.Append(col.DbUpdateValue);
11501152
else
11511153
{
1152-
var valsameIf = col.Attribute.MapType.IsNumberType() || col.Attribute.MapType == typeof(string) || col.Attribute.MapType.NullableTypeOrThis().IsEnum;
1154+
var valsameIf = col.Attribute.MapType.IsNumberType() ||
1155+
new[] { typeof(string), typeof(DateTime), typeof(DateTime?) }.Contains(col.Attribute.MapType) ||
1156+
col.Attribute.MapType.NullableTypeOrThis().IsEnum;
11531157
var ds = _source.Select(a => col.GetDbValue(a)).ToArray();
11541158
if (valsameIf && ds.All(a => object.Equals(a, ds[0])))
11551159
{

Providers/FreeSql.Provider.Custom/MySql/Curd/CustomMySqlInsertOrUpdate.cs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Data.Common;
55
using System.Linq;
66
using System.Text;
7+
using System.Text.RegularExpressions;
78

89
namespace FreeSql.Custom.MySql
910
{
@@ -62,10 +63,26 @@ string getInsertSql(List<T1> data, bool flagInsert, bool noneParameter)
6263
insert.InsertIdentity();
6364
if (_doNothing == false)
6465
{
65-
var cols = _table.Columns.Values.Where(a => _tempPrimarys.Contains(a) == false && a.Attribute.CanUpdate == true && a.Attribute.IsIdentity == false && _updateIgnore.ContainsKey(a.Attribute.Name) == false);
66+
var cols = _table.Columns.Values.Where(a => _updateSetDict.ContainsKey(a.Attribute.Name) ||
67+
_tempPrimarys.Contains(a) == false && a.Attribute.CanUpdate == true && a.Attribute.IsIdentity == false && _updateIgnore.ContainsKey(a.Attribute.Name) == false);
6668
sql = new CustomMySqlOnDuplicateKeyUpdate<T1>(insert)
6769
.UpdateColumns(cols.Select(a => a.Attribute.Name).ToArray())
6870
.ToSql();
71+
if (_updateSetDict.Any())
72+
{
73+
var findregex = new Regex("(t1|t2)." + _commonUtils.QuoteSqlName("test").Replace("test", "(\\w+)"));
74+
foreach (var usd in _updateSetDict)
75+
{
76+
var field = _commonUtils.QuoteSqlName(usd.Key);
77+
var findsql = $"{field} = VALUES({field})";
78+
var usdval = findregex.Replace(usd.Value, m =>
79+
{
80+
if (m.Groups[1].Value == "t1") return _commonUtils.QuoteSqlName(m.Groups[2].Value);
81+
return $"VALUES({_commonUtils.QuoteSqlName(m.Groups[2].Value)})";
82+
});
83+
sql = sql.Replace(findsql, $"{field} = {usdval}");
84+
}
85+
}
6986
}
7087
else
7188
{

Providers/FreeSql.Provider.Custom/Oracle/Curd/CustomOracleInsertOrUpdate.cs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,18 @@ string getMergeSql(List<T1> data)
3939
WriteSourceSelectUnionAll(data, sb, dbParams);
4040
sb.Append(" ) t2 ON (").Append(string.Join(" AND ", _tempPrimarys.Select(a => $"t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{_commonUtils.QuoteSqlName(a.Attribute.Name)}"))).Append(") \r\n");
4141

42-
var cols = _table.Columns.Values.Where(a => _tempPrimarys.Contains(a) == false && a.Attribute.CanUpdate == true && a.Attribute.IsIdentity == false && _updateIgnore.ContainsKey(a.Attribute.Name) == false);
42+
var cols = _table.Columns.Values.Where(a => _updateSetDict.ContainsKey(a.Attribute.Name) ||
43+
_tempPrimarys.Contains(a) == false && a.Attribute.CanUpdate == true && a.Attribute.IsIdentity == false && _updateIgnore.ContainsKey(a.Attribute.Name) == false);
4344
if (_doNothing == false && cols.Any())
4445
sb.Append("WHEN MATCHED THEN \r\n")
4546
.Append(" update set ").Append(string.Join(", ", cols.Select(a =>
46-
a.Attribute.IsVersion && a.Attribute.MapType != typeof(byte[]) ?
47-
$"{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} + 1" :
48-
$"{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{_commonUtils.QuoteSqlName(a.Attribute.Name)}"
49-
))).Append(" \r\n");
47+
{
48+
if (_updateSetDict.TryGetValue(a.Attribute.Name, out var valsql))
49+
return $"{_commonUtils.QuoteSqlName(a.Attribute.Name)} = {valsql}";
50+
return a.Attribute.IsVersion && a.Attribute.MapType != typeof(byte[]) ?
51+
$"{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} + 1" :
52+
$"{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{_commonUtils.QuoteSqlName(a.Attribute.Name)}";
53+
}))).Append(" \r\n");
5054

5155
cols = _table.Columns.Values.Where(a => a.Attribute.CanInsert == true);
5256
if (tempPrimaryIsIdentity == false) cols = cols.Where(a => a.Attribute.IsIdentity == false || string.IsNullOrEmpty(a.DbInsertValue) == false);

Providers/FreeSql.Provider.Custom/PostgreSQL/Curd/CustomPostgreSQLInsertOrUpdate.cs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Data.Common;
44
using System.Linq;
55
using System.Text;
6+
using System.Text.RegularExpressions;
67

78
namespace FreeSql.Custom.PostgreSQL
89
{
@@ -57,11 +58,29 @@ string getInsertSql(List<T1> data, bool flagInsert, bool noneParameter)
5758
{
5859
var ocdu = new CustomPostgreSQLOnConflictDoUpdate<T1>(insert.InsertIdentity());
5960
ocdu._tempPrimarys = _tempPrimarys;
60-
var cols = _table.Columns.Values.Where(a => _tempPrimarys.Contains(a) == false && a.Attribute.CanUpdate == true && a.Attribute.IsIdentity == false && _updateIgnore.ContainsKey(a.Attribute.Name) == false);
61+
var cols = _table.Columns.Values.Where(a => _updateSetDict.ContainsKey(a.Attribute.Name) ||
62+
_tempPrimarys.Contains(a) == false && a.Attribute.CanUpdate == true && a.Attribute.IsIdentity == false && _updateIgnore.ContainsKey(a.Attribute.Name) == false);
6163
ocdu.UpdateColumns(cols.Select(a => a.Attribute.Name).ToArray());
6264
if (_doNothing == true || cols.Any() == false)
6365
ocdu.DoNothing();
6466
sql = ocdu.ToSql();
67+
68+
if (_updateSetDict.Any())
69+
{
70+
var findregex = new Regex("(t1|t2)." + _commonUtils.QuoteSqlName("test").Replace("test", "(\\w+)"));
71+
var tableName = _commonUtils.QuoteSqlName(TableRuleInvoke());
72+
foreach (var usd in _updateSetDict)
73+
{
74+
var field = _commonUtils.QuoteSqlName(usd.Key);
75+
var findsql = $"{field} = EXCLUDED.{field}";
76+
var usdval = findregex.Replace(usd.Value, m =>
77+
{
78+
if (m.Groups[1].Value == "t1") return $"{tableName}.{_commonUtils.QuoteSqlName(m.Groups[2].Value)}";
79+
return $"EXCLUDED.{_commonUtils.QuoteSqlName(m.Groups[2].Value)}";
80+
});
81+
sql = sql.Replace(findsql, $"{field} = {usdval}");
82+
}
83+
}
6584
}
6685
if (string.IsNullOrEmpty(sql)) return null;
6786
if (insert._params?.Any() == true) dbParams.AddRange(insert._params);

Providers/FreeSql.Provider.Custom/SqlServer/Curd/CustomSqlServerInsertOrUpdate.cs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,18 @@ string getMergeSql(List<T1> data)
4141
WriteSourceSelectUnionAll(data, sb, dbParams);
4242
sb.Append(" ) t2 ON (").Append(string.Join(" AND ", _tempPrimarys.Select(a => $"t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{_commonUtils.QuoteSqlName(a.Attribute.Name)}"))).Append(") \r\n");
4343

44-
var cols = _table.Columns.Values.Where(a => _tempPrimarys.Contains(a) == false && a.Attribute.CanUpdate == true && a.Attribute.IsIdentity == false && _updateIgnore.ContainsKey(a.Attribute.Name) == false);
44+
var cols = _table.Columns.Values.Where(a => _updateSetDict.ContainsKey(a.Attribute.Name) ||
45+
_tempPrimarys.Contains(a) == false && a.Attribute.CanUpdate == true && a.Attribute.IsIdentity == false && _updateIgnore.ContainsKey(a.Attribute.Name) == false);
4546
if (_doNothing == false && cols.Any())
4647
sb.Append("WHEN MATCHED THEN \r\n")
4748
.Append(" update set ").Append(string.Join(", ", cols.Select(a =>
48-
a.Attribute.IsVersion && a.Attribute.MapType != typeof(byte[]) ?
49-
$"{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} + 1" :
50-
$"{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{_commonUtils.QuoteSqlName(a.Attribute.Name)}"
51-
))).Append(" \r\n");
49+
{
50+
if (_updateSetDict.TryGetValue(a.Attribute.Name, out var valsql))
51+
return $"{_commonUtils.QuoteSqlName(a.Attribute.Name)} = {valsql}";
52+
return a.Attribute.IsVersion && a.Attribute.MapType != typeof(byte[]) ?
53+
$"{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} + 1" :
54+
$"{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{_commonUtils.QuoteSqlName(a.Attribute.Name)}";
55+
}))).Append(" \r\n");
5256

5357
cols = _table.Columns.Values.Where(a => a.Attribute.CanInsert == true);
5458
if (tempPrimaryIsIdentity == false) cols = cols.Where(a => a.Attribute.IsIdentity == false || string.IsNullOrEmpty(a.DbInsertValue) == false);

0 commit comments

Comments
 (0)