- 补充 fsql.InsertOrUpdate UpdateColumns 数据存在时只更新指定的字段;

This commit is contained in:
28810 2020-07-29 15:32:14 +08:00
parent a8d1db8614
commit 06b301395f
19 changed files with 89 additions and 26 deletions

View File

@ -125,6 +125,13 @@
清空状态数据 清空状态数据
</summary> </summary>
</member> </member>
<member name="M:FreeSql.DbSet`1.RemoveAsync(System.Linq.Expressions.Expression{System.Func{`0,System.Boolean}})">
<summary>
根据 lambda 条件删除数据
</summary>
<param name="predicate"></param>
<returns></returns>
</member>
<member name="M:FreeSql.DbSet`1.Add(`0)"> <member name="M:FreeSql.DbSet`1.Add(`0)">
<summary> <summary>
添加 添加

View File

@ -296,6 +296,7 @@ namespace FreeSql.Tests
public void EnableAddOrUpdateNavigateList_OneToMany() public void EnableAddOrUpdateNavigateList_OneToMany()
{ {
var repo = g.sqlite.GetRepository<Cagetory>(); var repo = g.sqlite.GetRepository<Cagetory>();
repo.DbContextOptions.EnableAddOrUpdateNavigateList = true;
var cts = new[] { var cts = new[] {
new Cagetory new Cagetory
{ {

View File

@ -159,6 +159,8 @@ namespace FreeSql.Tests
[Fact] [Fact]
public void Test03() public void Test03()
{ {
var sqlxx = g.pgsql.InsertOrUpdate<userinfo>().SetSource(new userinfo { userid = 10 }).UpdateColumns(a => new { a.birthday, a.CardNo }).ToSql();
var aff1 = g.sqlite.GetRepository<Edi, long>().Delete(10086); var aff1 = g.sqlite.GetRepository<Edi, long>().Delete(10086);
var aff2 = g.sqlite.Delete<Edi>(10086).ExecuteAffrows(); var aff2 = g.sqlite.Delete<Edi>(10086).ExecuteAffrows();
Assert.Equal(aff1, aff2); Assert.Equal(aff1, aff2);

View File

@ -1165,6 +1165,20 @@
</summary> </summary>
<returns></returns> <returns></returns>
</member> </member>
<member name="M:FreeSql.IInsertOrUpdate`1.UpdateColumns(System.Linq.Expressions.Expression{System.Func{`0,System.Object}})">
<summary>
当记录存在时指定只更新的字段UpdateColumns(a => a.Name) | UpdateColumns(a => new{a.Name,a.Time}) | UpdateColumns(a => new[]{"name","time"})
</summary>
<param name="columns">lambda选择列</param>
<returns></returns>
</member>
<member name="M:FreeSql.IInsertOrUpdate`1.UpdateColumns(System.String[])">
<summary>
当记录存在时,指定只更新的字段
</summary>
<param name="columns">属性名,或者字段名</param>
<returns></returns>
</member>
<member name="M:FreeSql.IInsertOrUpdate`1.AsTable(System.Func{System.String,System.String})"> <member name="M:FreeSql.IInsertOrUpdate`1.AsTable(System.Func{System.String,System.String})">
<summary> <summary>
设置表名规则,可用于分库/分表参数1默认表名返回值新表名 设置表名规则,可用于分库/分表参数1默认表名返回值新表名

View File

@ -42,6 +42,19 @@ namespace FreeSql
/// <returns></returns> /// <returns></returns>
IInsertOrUpdate<T1> IfExistsDoNothing(); IInsertOrUpdate<T1> IfExistsDoNothing();
/// <summary>
/// 当记录存在时指定只更新的字段UpdateColumns(a => a.Name) | UpdateColumns(a => new{a.Name,a.Time}) | UpdateColumns(a => new[]{"name","time"})
/// </summary>
/// <param name="columns">lambda选择列</param>
/// <returns></returns>
IInsertOrUpdate<T1> UpdateColumns(Expression<Func<T1, object>> columns);
/// <summary>
/// 当记录存在时,指定只更新的字段
/// </summary>
/// <param name="columns">属性名,或者字段名</param>
/// <returns></returns>
IInsertOrUpdate<T1> UpdateColumns(string[] columns);
/// <summary> /// <summary>
/// 设置表名规则,可用于分库/分表参数1默认表名返回值新表名 /// 设置表名规则,可用于分库/分表参数1默认表名返回值新表名
/// </summary> /// </summary>

View File

@ -15,17 +15,18 @@ namespace FreeSql.Internal.CommonProvider
public abstract partial class InsertOrUpdateProvider<T1> : IInsertOrUpdate<T1> where T1 : class public abstract partial class InsertOrUpdateProvider<T1> : IInsertOrUpdate<T1> where T1 : class
{ {
protected IFreeSql _orm; public IFreeSql _orm;
protected CommonUtils _commonUtils; public CommonUtils _commonUtils;
protected CommonExpression _commonExpression; public CommonExpression _commonExpression;
protected List<T1> _source = new List<T1>(); public List<T1> _source = new List<T1>();
protected bool _doNothing = false; public bool _doNothing = false;
protected Dictionary<string, bool> _auditValueChangedDict = new Dictionary<string, bool>(StringComparer.CurrentCultureIgnoreCase); public Dictionary<string, bool> _updateIgnore = new Dictionary<string, bool>(StringComparer.CurrentCultureIgnoreCase);
protected TableInfo _table; public Dictionary<string, bool> _auditValueChangedDict = new Dictionary<string, bool>(StringComparer.CurrentCultureIgnoreCase);
protected Func<string, string> _tableRule; public TableInfo _table;
protected DbParameter[] _params; public Func<string, string> _tableRule;
protected DbTransaction _transaction; public DbParameter[] _params;
protected DbConnection _connection; public DbTransaction _transaction;
public DbConnection _connection;
public ColumnInfo IdentityColumn { get; } public ColumnInfo IdentityColumn { get; }
public InsertOrUpdateProvider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) public InsertOrUpdateProvider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
@ -57,6 +58,17 @@ namespace FreeSql.Internal.CommonProvider
return this; return this;
} }
public IInsertOrUpdate<T1> UpdateColumns(Expression<Func<T1, object>> columns) => UpdateColumns(_commonExpression.ExpressionSelectColumns_MemberAccess_New_NewArrayInit(null, columns?.Body, false, null));
public IInsertOrUpdate<T1> UpdateColumns(string[] columns)
{
var cols = columns.Distinct().ToDictionary(a => a);
_updateIgnore.Clear();
foreach (var col in _table.Columns.Values)
if (cols.ContainsKey(col.Attribute.Name) == false && cols.ContainsKey(col.CsName) == false)
_updateIgnore.Add(col.Attribute.Name, true);
return this;
}
public static void AuditDataValue(object sender, IEnumerable<T1> data, IFreeSql orm, TableInfo table, Dictionary<string, bool> changedDict) public static void AuditDataValue(object sender, IEnumerable<T1> data, IFreeSql orm, TableInfo table, Dictionary<string, bool> changedDict)
{ {
if (data?.Any() != true) return; if (data?.Any() != true) return;

View File

@ -37,7 +37,7 @@ namespace FreeSql.Dameng.Curd
WriteSourceSelectUnionAll(data, sb, dbParams); WriteSourceSelectUnionAll(data, sb, dbParams);
sb.Append(" ) t2 ON (").Append(string.Join(" AND ", _table.Primarys.Select(a => $"t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{a.Attribute.Name}"))).Append(") \r\n"); sb.Append(" ) t2 ON (").Append(string.Join(" AND ", _table.Primarys.Select(a => $"t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{a.Attribute.Name}"))).Append(") \r\n");
var cols = _table.Columns.Values.Where(a => a.Attribute.IsPrimary == false && a.Attribute.CanUpdate == true); var cols = _table.Columns.Values.Where(a => a.Attribute.IsPrimary == false && a.Attribute.CanUpdate == true && _updateIgnore.ContainsKey(a.Attribute.Name) == false);
if (_doNothing == false && cols.Any()) if (_doNothing == false && cols.Any())
sb.Append("WHEN MATCHED THEN \r\n") sb.Append("WHEN MATCHED THEN \r\n")
.Append(" update set ").Append(string.Join(", ", cols.Select(a => .Append(" update set ").Append(string.Join(", ", cols.Select(a =>

View File

@ -44,7 +44,12 @@ namespace FreeSql.MySql.Curd
{ {
insert.InsertIdentity(); insert.InsertIdentity();
if (_doNothing == false) if (_doNothing == false)
sql = new OnDuplicateKeyUpdate<T1>(insert).ToSql(); {
var cols = _table.Columns.Values.Where(a => a.Attribute.IsPrimary == false && a.Attribute.CanUpdate == true && _updateIgnore.ContainsKey(a.Attribute.Name) == false);
sql = new OnDuplicateKeyUpdate<T1>(insert)
.UpdateColumns(cols.Select(a => a.Attribute.Name).ToArray())
.ToSql();
}
else else
{ {
if (_table.Primarys.Any() == false) throw new Exception($"fsql.InsertOrUpdate + IfExistsDoNothing + MySql 要求实体类 {_table.CsName} 必须有主键"); if (_table.Primarys.Any() == false) throw new Exception($"fsql.InsertOrUpdate + IfExistsDoNothing + MySql 要求实体类 {_table.CsName} 必须有主键");

View File

@ -37,7 +37,7 @@ namespace FreeSql.Odbc.Dameng
WriteSourceSelectUnionAll(data, sb, dbParams); WriteSourceSelectUnionAll(data, sb, dbParams);
sb.Append(" ) t2 ON (").Append(string.Join(" AND ", _table.Primarys.Select(a => $"t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{a.Attribute.Name}"))).Append(") \r\n"); sb.Append(" ) t2 ON (").Append(string.Join(" AND ", _table.Primarys.Select(a => $"t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{a.Attribute.Name}"))).Append(") \r\n");
var cols = _table.Columns.Values.Where(a => a.Attribute.IsPrimary == false && a.Attribute.CanUpdate == true); var cols = _table.Columns.Values.Where(a => a.Attribute.IsPrimary == false && a.Attribute.CanUpdate == true && _updateIgnore.ContainsKey(a.Attribute.Name) == false);
if (_doNothing == false && cols.Any()) if (_doNothing == false && cols.Any())
sb.Append("WHEN MATCHED THEN \r\n") sb.Append("WHEN MATCHED THEN \r\n")
.Append(" update set ").Append(string.Join(", ", cols.Select(a => .Append(" update set ").Append(string.Join(", ", cols.Select(a =>

View File

@ -43,8 +43,9 @@ namespace FreeSql.Odbc.KingbaseES
else else
{ {
var ocdu = new OdbcKingbaseESOnConflictDoUpdate<T1>(insert.InsertIdentity()); var ocdu = new OdbcKingbaseESOnConflictDoUpdate<T1>(insert.InsertIdentity());
ocdu.IgnoreColumns(_table.Columns.Values.Where(a => a.Attribute.CanUpdate == false).Select(a => a.Attribute.Name).ToArray()); var cols = _table.Columns.Values.Where(a => a.Attribute.IsPrimary == false && a.Attribute.CanUpdate == true && _updateIgnore.ContainsKey(a.Attribute.Name) == false);
if (_doNothing == true || _table.Columns.Values.Where(a => a.Attribute.IsPrimary == false && a.Attribute.CanUpdate == true).Any() == false) ocdu.UpdateColumns(cols.Select(a => a.Attribute.Name).ToArray());
if (_doNothing == true || cols.Any() == false)
ocdu.DoNothing(); ocdu.DoNothing();
sql = ocdu.ToSql(); sql = ocdu.ToSql();
} }

View File

@ -43,7 +43,12 @@ namespace FreeSql.Odbc.MySql
{ {
insert.InsertIdentity(); insert.InsertIdentity();
if (_doNothing == false) if (_doNothing == false)
sql = new OdbcMySqlOnDuplicateKeyUpdate<T1>(insert).ToSql(); {
var cols = _table.Columns.Values.Where(a => a.Attribute.IsPrimary == false && a.Attribute.CanUpdate == true && _updateIgnore.ContainsKey(a.Attribute.Name) == false);
sql = new OdbcMySqlOnDuplicateKeyUpdate<T1>(insert)
.UpdateColumns(cols.Select(a => a.Attribute.Name).ToArray())
.ToSql();
}
else else
{ {
if (_table.Primarys.Any() == false) throw new Exception($"fsql.InsertOrUpdate + IfExistsDoNothing + MySql 要求实体类 {_table.CsName} 必须有主键"); if (_table.Primarys.Any() == false) throw new Exception($"fsql.InsertOrUpdate + IfExistsDoNothing + MySql 要求实体类 {_table.CsName} 必须有主键");

View File

@ -37,7 +37,7 @@ namespace FreeSql.Odbc.Oracle
WriteSourceSelectUnionAll(data, sb, dbParams); WriteSourceSelectUnionAll(data, sb, dbParams);
sb.Append(" ) t2 ON (").Append(string.Join(" AND ", _table.Primarys.Select(a => $"t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{a.Attribute.Name}"))).Append(") \r\n"); sb.Append(" ) t2 ON (").Append(string.Join(" AND ", _table.Primarys.Select(a => $"t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{a.Attribute.Name}"))).Append(") \r\n");
var cols = _table.Columns.Values.Where(a => a.Attribute.IsPrimary == false && a.Attribute.CanUpdate == true); var cols = _table.Columns.Values.Where(a => a.Attribute.IsPrimary == false && a.Attribute.CanUpdate == true && _updateIgnore.ContainsKey(a.Attribute.Name) == false);
if (_doNothing == false && cols.Any()) if (_doNothing == false && cols.Any())
sb.Append("WHEN MATCHED THEN \r\n") sb.Append("WHEN MATCHED THEN \r\n")
.Append(" update set ").Append(string.Join(", ", cols.Select(a => .Append(" update set ").Append(string.Join(", ", cols.Select(a =>

View File

@ -41,8 +41,9 @@ namespace FreeSql.Odbc.PostgreSQL
else else
{ {
var ocdu = new OdbcPostgreSQLOnConflictDoUpdate<T1>(insert.InsertIdentity()); var ocdu = new OdbcPostgreSQLOnConflictDoUpdate<T1>(insert.InsertIdentity());
ocdu.IgnoreColumns(_table.Columns.Values.Where(a => a.Attribute.CanUpdate == false).Select(a => a.Attribute.Name).ToArray()); var cols = _table.Columns.Values.Where(a => a.Attribute.IsPrimary == false && a.Attribute.CanUpdate == true && _updateIgnore.ContainsKey(a.Attribute.Name) == false);
if (_doNothing == true || _table.Columns.Values.Where(a => a.Attribute.IsPrimary == false && a.Attribute.CanUpdate == true).Any() == false) ocdu.UpdateColumns(cols.Select(a => a.Attribute.Name).ToArray());
if (_doNothing == true || cols.Any() == false)
ocdu.DoNothing(); ocdu.DoNothing();
sql = ocdu.ToSql(); sql = ocdu.ToSql();
} }

View File

@ -39,7 +39,7 @@ namespace FreeSql.Odbc.SqlServer
WriteSourceSelectUnionAll(data, sb, dbParams); WriteSourceSelectUnionAll(data, sb, dbParams);
sb.Append(" ) t2 ON (").Append(string.Join(" AND ", _table.Primarys.Select(a => $"t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{a.Attribute.Name}"))).Append(") \r\n"); sb.Append(" ) t2 ON (").Append(string.Join(" AND ", _table.Primarys.Select(a => $"t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{a.Attribute.Name}"))).Append(") \r\n");
var cols = _table.Columns.Values.Where(a => a.Attribute.IsPrimary == false && a.Attribute.CanUpdate == true); var cols = _table.Columns.Values.Where(a => a.Attribute.IsPrimary == false && a.Attribute.CanUpdate == true && _updateIgnore.ContainsKey(a.Attribute.Name) == false);
if (_doNothing == false && cols.Any()) if (_doNothing == false && cols.Any())
sb.Append("WHEN MATCHED THEN \r\n") sb.Append("WHEN MATCHED THEN \r\n")
.Append(" update set ").Append(string.Join(", ", cols.Select(a => .Append(" update set ").Append(string.Join(", ", cols.Select(a =>

View File

@ -37,7 +37,7 @@ namespace FreeSql.Oracle.Curd
WriteSourceSelectUnionAll(data, sb, dbParams); WriteSourceSelectUnionAll(data, sb, dbParams);
sb.Append(" ) t2 ON (").Append(string.Join(" AND ", _table.Primarys.Select(a => $"t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{a.Attribute.Name}"))).Append(") \r\n"); sb.Append(" ) t2 ON (").Append(string.Join(" AND ", _table.Primarys.Select(a => $"t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{a.Attribute.Name}"))).Append(") \r\n");
var cols = _table.Columns.Values.Where(a => a.Attribute.IsPrimary == false && a.Attribute.CanUpdate == true); var cols = _table.Columns.Values.Where(a => a.Attribute.IsPrimary == false && a.Attribute.CanUpdate == true && _updateIgnore.ContainsKey(a.Attribute.Name) == false);
if (_doNothing == false && cols.Any()) if (_doNothing == false && cols.Any())
sb.Append("WHEN MATCHED THEN \r\n") sb.Append("WHEN MATCHED THEN \r\n")
.Append(" update set ").Append(string.Join(", ", cols.Select(a => .Append(" update set ").Append(string.Join(", ", cols.Select(a =>

View File

@ -41,8 +41,9 @@ namespace FreeSql.PostgreSQL.Curd
else else
{ {
var ocdu = new OnConflictDoUpdate<T1>(insert.InsertIdentity()); var ocdu = new OnConflictDoUpdate<T1>(insert.InsertIdentity());
ocdu.IgnoreColumns(_table.Columns.Values.Where(a => a.Attribute.CanUpdate == false).Select(a => a.Attribute.Name).ToArray()); var cols = _table.Columns.Values.Where(a => a.Attribute.IsPrimary == false && a.Attribute.CanUpdate == true && _updateIgnore.ContainsKey(a.Attribute.Name) == false);
if (_doNothing == true || _table.Columns.Values.Where(a => a.Attribute.IsPrimary == false && a.Attribute.CanUpdate == true).Any() == false) ocdu.UpdateColumns(cols.Select(a => a.Attribute.Name).ToArray());
if (_doNothing == true || cols.Any() == false)
ocdu.DoNothing(); ocdu.DoNothing();
sql = ocdu.ToSql(); sql = ocdu.ToSql();
} }

View File

@ -37,7 +37,7 @@ namespace FreeSql.ShenTong.Curd
WriteSourceSelectUnionAll(data, sb, dbParams); WriteSourceSelectUnionAll(data, sb, dbParams);
sb.Append(" ) t2 ON (").Append(string.Join(" AND ", _table.Primarys.Select(a => $"t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{a.Attribute.Name}"))).Append(") \r\n"); sb.Append(" ) t2 ON (").Append(string.Join(" AND ", _table.Primarys.Select(a => $"t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{a.Attribute.Name}"))).Append(") \r\n");
var cols = _table.Columns.Values.Where(a => a.Attribute.IsPrimary == false && a.Attribute.CanUpdate == true); var cols = _table.Columns.Values.Where(a => a.Attribute.IsPrimary == false && a.Attribute.CanUpdate == true && _updateIgnore.ContainsKey(a.Attribute.Name) == false);
if (_doNothing == false && cols.Any()) if (_doNothing == false && cols.Any())
sb.Append("WHEN MATCHED THEN \r\n") sb.Append("WHEN MATCHED THEN \r\n")
.Append(" update set ").Append(string.Join(", ", cols.Select(a => .Append(" update set ").Append(string.Join(", ", cols.Select(a =>

View File

@ -39,7 +39,7 @@ namespace FreeSql.SqlServer.Curd
WriteSourceSelectUnionAll(data, sb, dbParams); WriteSourceSelectUnionAll(data, sb, dbParams);
sb.Append(" ) t2 ON (").Append(string.Join(" AND ", _table.Primarys.Select(a => $"t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{a.Attribute.Name}"))).Append(") \r\n"); sb.Append(" ) t2 ON (").Append(string.Join(" AND ", _table.Primarys.Select(a => $"t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{a.Attribute.Name}"))).Append(") \r\n");
var cols = _table.Columns.Values.Where(a => a.Attribute.IsPrimary == false && a.Attribute.CanUpdate == true); var cols = _table.Columns.Values.Where(a => a.Attribute.IsPrimary == false && a.Attribute.CanUpdate == true && _updateIgnore.ContainsKey(a.Attribute.Name) == false);
if (_doNothing == false && cols.Any()) if (_doNothing == false && cols.Any())
sb.Append("WHEN MATCHED THEN \r\n") sb.Append("WHEN MATCHED THEN \r\n")
.Append(" update set ").Append(string.Join(", ", cols.Select(a => .Append(" update set ").Append(string.Join(", ", cols.Select(a =>

View File

@ -44,6 +44,7 @@ namespace FreeSql.Sqlite.Curd
insert.InsertIdentity(); insert.InsertIdentity();
if (_doNothing == false) if (_doNothing == false)
{ {
if (_updateIgnore.Any()) throw new Exception($"fsql.InsertOrUpdate Sqlite 无法完成 UpdateColumns 操作");
sql = insert.ToSql(); sql = insert.ToSql();
if (sql?.StartsWith("INSERT INTO ") == true) if (sql?.StartsWith("INSERT INTO ") == true)
sql = $"REPLACE INTO {sql.Substring("INSERT INTO ".Length)}"; sql = $"REPLACE INTO {sql.Substring("INSERT INTO ".Length)}";