mirror of
https://github.com/nsnail/FreeSql.git
synced 2025-06-19 12:28:15 +08:00
- 增加 IFreeSql.InsertOrUpdate 方法 #316
This commit is contained in:
@ -0,0 +1,43 @@
|
||||
using FreeSql.Internal;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace FreeSql.Odbc.Dameng
|
||||
{
|
||||
|
||||
class OdbcDamengInsertOrUpdate<T1> : Internal.CommonProvider.InsertOrUpdateProvider<T1> where T1 : class
|
||||
{
|
||||
public OdbcDamengInsertOrUpdate(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
|
||||
: base(orm, commonUtils, commonExpression)
|
||||
{
|
||||
}
|
||||
|
||||
public override string ToSql()
|
||||
{
|
||||
if (_source?.Any() != true) return null;
|
||||
if (_table.Primarys.Any() == false) throw new Exception($"InsertOrUpdate 功能要求实体类 {_table.CsName} 必须有主键");
|
||||
|
||||
var sb = new StringBuilder().Append("MERGE INTO ").Append(_commonUtils.QuoteSqlName(TableRuleInvoke())).Append(" t1 \r\n")
|
||||
.Append("USING (");
|
||||
WriteSourceSelectUnionAll(sb);
|
||||
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);
|
||||
if (cols.Any())
|
||||
sb.Append("WHEN MATCHED THEN \r\n")
|
||||
.Append(" update set ").Append(string.Join(", ", cols.Select(a =>
|
||||
a.Attribute.IsVersion ?
|
||||
$"{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} + 1" :
|
||||
$"{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{a.Attribute.Name}"
|
||||
))).Append(" \r\n");
|
||||
|
||||
cols = _table.Columns.Values;
|
||||
sb.Append("WHEN NOT MATCHED THEN \r\n")
|
||||
.Append(" insert (").Append(string.Join(", ", cols.Select(a => _commonUtils.QuoteSqlName(a.Attribute.Name)))).Append(") \r\n")
|
||||
.Append(" values (").Append(string.Join(", ", cols.Select(a => $"t2.{a.Attribute.Name}"))).Append(")");
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
@ -23,6 +23,7 @@ namespace FreeSql.Odbc.Dameng
|
||||
public IUpdate<T1> Update<T1>(object dywhere) where T1 : class => new OdbcDamengUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
|
||||
public IDelete<T1> Delete<T1>() where T1 : class => new OdbcDamengDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, null);
|
||||
public IDelete<T1> Delete<T1>(object dywhere) where T1 : class => new OdbcDamengDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
|
||||
public IInsertOrUpdate<T1> InsertOrUpdate<T1>() where T1 : class => new OdbcDamengInsertOrUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression);
|
||||
|
||||
public IAdo Ado { get; }
|
||||
public IAop Aop { get; }
|
||||
|
@ -26,6 +26,7 @@ namespace FreeSql.Odbc.Default
|
||||
public IUpdate<T1> Update<T1>(object dywhere) where T1 : class => new OdbcUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
|
||||
public IDelete<T1> Delete<T1>() where T1 : class => new OdbcDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, null);
|
||||
public IDelete<T1> Delete<T1>(object dywhere) where T1 : class => new OdbcDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
|
||||
public IInsertOrUpdate<T1> InsertOrUpdate<T1>() where T1 : class => throw new NotImplementedException();
|
||||
|
||||
public IAdo Ado { get; }
|
||||
public IAop Aop { get; }
|
||||
|
@ -1,4 +1,5 @@
|
||||
using FreeSql.Internal;
|
||||
using FreeSql.Internal.Model;
|
||||
using FreeSql.Internal.ObjectPool;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@ -17,11 +18,30 @@ namespace FreeSql.Odbc.MySql
|
||||
{
|
||||
}
|
||||
|
||||
internal bool InternalIsIgnoreInto = false;
|
||||
internal IFreeSql InternalOrm => _orm;
|
||||
internal TableInfo InternalTable => _table;
|
||||
internal DbParameter[] InternalParams => _params;
|
||||
internal DbConnection InternalConnection => _connection;
|
||||
internal DbTransaction InternalTransaction => _transaction;
|
||||
internal CommonUtils InternalCommonUtils => _commonUtils;
|
||||
internal CommonExpression InternalCommonExpression => _commonExpression;
|
||||
internal List<T1> InternalSource => _source;
|
||||
internal Dictionary<string, bool> InternalIgnore => _ignore;
|
||||
internal void InternalClearData() => ClearData();
|
||||
|
||||
public override int ExecuteAffrows() => base.SplitExecuteAffrows(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
|
||||
public override long ExecuteIdentity() => base.SplitExecuteIdentity(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
|
||||
public override List<T1> ExecuteInserted() => base.SplitExecuteInserted(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
|
||||
|
||||
|
||||
public override string ToSql()
|
||||
{
|
||||
if (InternalIsIgnoreInto == false) return base.ToSqlValuesOrSelectUnionAll();
|
||||
var sql = base.ToSqlValuesOrSelectUnionAll();
|
||||
return $"INSERT IGNORE INTO {sql.Substring(12)}";
|
||||
}
|
||||
|
||||
protected override long RawExecuteIdentity()
|
||||
{
|
||||
var sql = this.ToSql();
|
||||
|
@ -0,0 +1,29 @@
|
||||
using FreeSql.Internal;
|
||||
using System.Linq;
|
||||
|
||||
namespace FreeSql.Odbc.MySql
|
||||
{
|
||||
|
||||
class OdbcMySqlInsertOrUpdate<T1> : Internal.CommonProvider.InsertOrUpdateProvider<T1> where T1 : class
|
||||
{
|
||||
public OdbcMySqlInsertOrUpdate(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
|
||||
: base(orm, commonUtils, commonExpression)
|
||||
{
|
||||
}
|
||||
|
||||
public override string ToSql()
|
||||
{
|
||||
if (_source?.Any() != true) return null;
|
||||
|
||||
var insert = _orm.Insert<T1>()
|
||||
.AsTable(_tableRule).AsType(_table.Type)
|
||||
.WithConnection(_connection)
|
||||
.WithTransaction(_transaction)
|
||||
.NoneParameter(true) as Internal.CommonProvider.InsertProvider<T1>;
|
||||
insert._source = _source;
|
||||
var sql = new OdbcMySqlOnDuplicateKeyUpdate<T1>(insert).ToSql();
|
||||
_params = insert._params;
|
||||
return sql;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,166 @@
|
||||
using FreeSql.Aop;
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FreeSql.Odbc.MySql
|
||||
{
|
||||
public class OdbcMySqlOnDuplicateKeyUpdate<T1> where T1 : class
|
||||
{
|
||||
internal OdbcMySqlInsert<T1> _mysqlInsert;
|
||||
internal OdbcMySqlUpdate<T1> _mysqlUpdatePriv;
|
||||
internal OdbcMySqlUpdate<T1> _mysqlUpdate => _mysqlUpdatePriv ?? (_mysqlUpdatePriv = new OdbcMySqlUpdate<T1>(_mysqlInsert.InternalOrm, _mysqlInsert.InternalCommonUtils, _mysqlInsert.InternalCommonExpression, null).NoneParameter().SetSource(_mysqlInsert.InternalSource) as OdbcMySqlUpdate<T1>);
|
||||
|
||||
public OdbcMySqlOnDuplicateKeyUpdate(IInsert<T1> insert)
|
||||
{
|
||||
_mysqlInsert = insert as OdbcMySqlInsert<T1>;
|
||||
if (_mysqlInsert == null) throw new Exception("OnDuplicateKeyUpdate 是 FreeSql.Provider.Odbc/MySql 特有的功能");
|
||||
}
|
||||
|
||||
protected void ClearData()
|
||||
{
|
||||
_mysqlInsert.InternalClearData();
|
||||
_mysqlUpdatePriv = null;
|
||||
}
|
||||
|
||||
public OdbcMySqlOnDuplicateKeyUpdate<T1> IgnoreColumns(Expression<Func<T1, object>> columns)
|
||||
{
|
||||
_mysqlUpdate.IgnoreColumns(columns);
|
||||
return this;
|
||||
}
|
||||
public OdbcMySqlOnDuplicateKeyUpdate<T1> UpdateColumns(Expression<Func<T1, object>> columns)
|
||||
{
|
||||
_mysqlUpdate.UpdateColumns(columns);
|
||||
return this;
|
||||
}
|
||||
public OdbcMySqlOnDuplicateKeyUpdate<T1> IgnoreColumns(string[] columns)
|
||||
{
|
||||
_mysqlUpdate.IgnoreColumns(columns);
|
||||
return this;
|
||||
}
|
||||
public OdbcMySqlOnDuplicateKeyUpdate<T1> UpdateColumns(string[] columns)
|
||||
{
|
||||
_mysqlUpdate.UpdateColumns(columns);
|
||||
return this;
|
||||
}
|
||||
|
||||
public OdbcMySqlOnDuplicateKeyUpdate<T1> Set<TMember>(Expression<Func<T1, TMember>> column, TMember value)
|
||||
{
|
||||
_mysqlUpdate.Set(column, value);
|
||||
return this;
|
||||
}
|
||||
public OdbcMySqlOnDuplicateKeyUpdate<T1> Set<TMember>(Expression<Func<T1, TMember>> exp)
|
||||
{
|
||||
_mysqlUpdate.Set(exp);
|
||||
return this;
|
||||
}
|
||||
public OdbcMySqlOnDuplicateKeyUpdate<T1> SetRaw(string sql)
|
||||
{
|
||||
_mysqlUpdate.SetRaw(sql);
|
||||
return this;
|
||||
}
|
||||
|
||||
public string ToSql()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.Append(_mysqlInsert.ToSql()).Append("\r\nON DUPLICATE KEY UPDATE\r\n");
|
||||
|
||||
var sbSetEmpty = _mysqlUpdate.InternalSbSet.Length == 0;
|
||||
var sbSetIncrEmpty = _mysqlUpdate.InternalSbSetIncr.Length == 0;
|
||||
if (sbSetEmpty == false || sbSetIncrEmpty == false)
|
||||
{
|
||||
if (sbSetEmpty == false) sb.Append(_mysqlUpdate.InternalSbSet.ToString().Substring(2));
|
||||
if (sbSetIncrEmpty == false) sb.Append(sbSetEmpty ? _mysqlUpdate.InternalSbSetIncr.ToString().Substring(2) : _mysqlUpdate.InternalSbSetIncr.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
var colidx = 0;
|
||||
foreach (var col in _mysqlInsert.InternalTable.Columns.Values)
|
||||
{
|
||||
if (col.Attribute.IsPrimary || _mysqlUpdate.InternalIgnore.ContainsKey(col.Attribute.Name)) continue;
|
||||
|
||||
if (colidx > 0) sb.Append(", \r\n");
|
||||
|
||||
if (col.Attribute.IsVersion == true)
|
||||
{
|
||||
var field = _mysqlInsert.InternalCommonUtils.QuoteSqlName(col.Attribute.Name);
|
||||
sb.Append(field).Append(" = ").Append(field).Append(" + 1");
|
||||
}
|
||||
else if (_mysqlInsert.InternalIgnore.ContainsKey(col.Attribute.Name))
|
||||
{
|
||||
var caseWhen = _mysqlUpdate.InternalWhereCaseSource(col.CsName, sqlval => sqlval).Trim();
|
||||
sb.Append(caseWhen);
|
||||
if (caseWhen.EndsWith(" END")) _mysqlUpdate.InternalToSqlCaseWhenEnd(sb, col);
|
||||
}
|
||||
else
|
||||
{
|
||||
var field = _mysqlInsert.InternalCommonUtils.QuoteSqlName(col.Attribute.Name);
|
||||
sb.Append(field).Append(" = VALUES(").Append(field).Append(")");
|
||||
}
|
||||
++colidx;
|
||||
}
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public long ExecuteAffrows()
|
||||
{
|
||||
var sql = this.ToSql();
|
||||
if (string.IsNullOrEmpty(sql)) return 0;
|
||||
|
||||
var before = new CurdBeforeEventArgs(_mysqlInsert.InternalTable.Type, _mysqlInsert.InternalTable, CurdType.Insert, sql, _mysqlInsert.InternalParams);
|
||||
_mysqlInsert.InternalOrm.Aop.CurdBeforeHandler?.Invoke(_mysqlInsert, before);
|
||||
long ret = 0;
|
||||
Exception exception = null;
|
||||
try
|
||||
{
|
||||
ret = _mysqlInsert.InternalOrm.Ado.ExecuteNonQuery(_mysqlInsert.InternalConnection, _mysqlInsert.InternalTransaction, CommandType.Text, sql, _mysqlInsert.InternalParams);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
exception = ex;
|
||||
throw ex;
|
||||
}
|
||||
finally
|
||||
{
|
||||
var after = new CurdAfterEventArgs(before, exception, ret);
|
||||
_mysqlInsert.InternalOrm.Aop.CurdAfterHandler?.Invoke(_mysqlInsert, after);
|
||||
ClearData();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if net40
|
||||
#else
|
||||
async public Task<long> ExecuteAffrowsAsync()
|
||||
{
|
||||
var sql = this.ToSql();
|
||||
if (string.IsNullOrEmpty(sql)) return 0;
|
||||
|
||||
var before = new CurdBeforeEventArgs(_mysqlInsert.InternalTable.Type, _mysqlInsert.InternalTable, CurdType.Insert, sql, _mysqlInsert.InternalParams);
|
||||
_mysqlInsert.InternalOrm.Aop.CurdBeforeHandler?.Invoke(_mysqlInsert, before);
|
||||
long ret = 0;
|
||||
Exception exception = null;
|
||||
try
|
||||
{
|
||||
ret = await _mysqlInsert.InternalOrm.Ado.ExecuteNonQueryAsync(_mysqlInsert.InternalConnection, _mysqlInsert.InternalTransaction, CommandType.Text, sql, _mysqlInsert.InternalParams);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
exception = ex;
|
||||
throw ex;
|
||||
}
|
||||
finally
|
||||
{
|
||||
var after = new CurdAfterEventArgs(before, exception, ret);
|
||||
_mysqlInsert.InternalOrm.Aop.CurdAfterHandler?.Invoke(_mysqlInsert, after);
|
||||
ClearData();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
@ -18,10 +18,16 @@ namespace FreeSql.Odbc.MySql
|
||||
{
|
||||
}
|
||||
|
||||
internal StringBuilder InternalSbSet => _set;
|
||||
internal StringBuilder InternalSbSetIncr => _setIncr;
|
||||
internal Dictionary<string, bool> InternalIgnore => _ignore;
|
||||
internal void InternalResetSource(List<T1> source) => _source = source;
|
||||
internal string InternalWhereCaseSource(string CsName, Func<string, string> thenValue) => WhereCaseSource(CsName, thenValue);
|
||||
internal void InternalToSqlCaseWhenEnd(StringBuilder sb, ColumnInfo col) => ToSqlCaseWhenEnd(sb, col);
|
||||
|
||||
public override int ExecuteAffrows() => base.SplitExecuteAffrows(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
|
||||
public override List<T1> ExecuteUpdated() => base.SplitExecuteUpdated(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
|
||||
|
||||
|
||||
protected override List<T1> RawExecuteUpdated()
|
||||
{
|
||||
var sql = this.ToSql();
|
||||
|
@ -28,6 +28,7 @@ namespace FreeSql.Odbc.MySql
|
||||
public IUpdate<T1> Update<T1>(object dywhere) where T1 : class => new OdbcMySqlUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
|
||||
public IDelete<T1> Delete<T1>() where T1 : class => new OdbcMySqlDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, null);
|
||||
public IDelete<T1> Delete<T1>(object dywhere) where T1 : class => new OdbcMySqlDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
|
||||
public IInsertOrUpdate<T1> InsertOrUpdate<T1>() where T1 : class => new OdbcMySqlInsertOrUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression);
|
||||
|
||||
public IAdo Ado { get; }
|
||||
public IAop Aop { get; }
|
||||
|
@ -0,0 +1,43 @@
|
||||
using FreeSql.Internal;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace FreeSql.Odbc.Oracle
|
||||
{
|
||||
|
||||
class OdbcOracleInsertOrUpdate<T1> : Internal.CommonProvider.InsertOrUpdateProvider<T1> where T1 : class
|
||||
{
|
||||
public OdbcOracleInsertOrUpdate(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
|
||||
: base(orm, commonUtils, commonExpression)
|
||||
{
|
||||
}
|
||||
|
||||
public override string ToSql()
|
||||
{
|
||||
if (_source?.Any() != true) return null;
|
||||
if (_table.Primarys.Any() == false) throw new Exception($"InsertOrUpdate 功能要求实体类 {_table.CsName} 必须有主键");
|
||||
|
||||
var sb = new StringBuilder().Append("MERGE INTO ").Append(_commonUtils.QuoteSqlName(TableRuleInvoke())).Append(" t1 \r\n")
|
||||
.Append("USING (");
|
||||
WriteSourceSelectUnionAll(sb);
|
||||
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);
|
||||
if (cols.Any())
|
||||
sb.Append("WHEN MATCHED THEN \r\n")
|
||||
.Append(" update set ").Append(string.Join(", ", cols.Select(a =>
|
||||
a.Attribute.IsVersion ?
|
||||
$"{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} + 1" :
|
||||
$"{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{a.Attribute.Name}"
|
||||
))).Append(" \r\n");
|
||||
|
||||
cols = _table.Columns.Values;
|
||||
sb.Append("WHEN NOT MATCHED THEN \r\n")
|
||||
.Append(" insert (").Append(string.Join(", ", cols.Select(a => _commonUtils.QuoteSqlName(a.Attribute.Name)))).Append(") \r\n")
|
||||
.Append(" values (").Append(string.Join(", ", cols.Select(a => $"t2.{a.Attribute.Name}"))).Append(")");
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
@ -23,6 +23,7 @@ namespace FreeSql.Odbc.Oracle
|
||||
public IUpdate<T1> Update<T1>(object dywhere) where T1 : class => new OdbcOracleUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
|
||||
public IDelete<T1> Delete<T1>() where T1 : class => new OdbcOracleDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, null);
|
||||
public IDelete<T1> Delete<T1>(object dywhere) where T1 : class => new OdbcOracleDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
|
||||
public IInsertOrUpdate<T1> InsertOrUpdate<T1>() where T1 : class => new OdbcOracleInsertOrUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression);
|
||||
|
||||
public IAdo Ado { get; }
|
||||
public IAop Aop { get; }
|
||||
|
@ -1,7 +1,9 @@
|
||||
using FreeSql.Internal;
|
||||
using FreeSql.Internal.Model;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
@ -16,6 +18,17 @@ namespace FreeSql.Odbc.PostgreSQL
|
||||
{
|
||||
}
|
||||
|
||||
internal IFreeSql InternalOrm => _orm;
|
||||
internal TableInfo InternalTable => _table;
|
||||
internal DbParameter[] InternalParams => _params;
|
||||
internal DbConnection InternalConnection => _connection;
|
||||
internal DbTransaction InternalTransaction => _transaction;
|
||||
internal CommonUtils InternalCommonUtils => _commonUtils;
|
||||
internal CommonExpression InternalCommonExpression => _commonExpression;
|
||||
internal List<T1> InternalSource => _source;
|
||||
internal Dictionary<string, bool> InternalIgnore => _ignore;
|
||||
internal void InternalClearData() => ClearData();
|
||||
|
||||
public override int ExecuteAffrows() => base.SplitExecuteAffrows(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
|
||||
public override long ExecuteIdentity() => base.SplitExecuteIdentity(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
|
||||
public override List<T1> ExecuteInserted() => base.SplitExecuteInserted(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
|
||||
|
@ -0,0 +1,33 @@
|
||||
using FreeSql.Internal;
|
||||
using System.Linq;
|
||||
|
||||
namespace FreeSql.Odbc.PostgreSQL
|
||||
{
|
||||
|
||||
class OdbcPostgreSQLInsertOrUpdate<T1> : Internal.CommonProvider.InsertOrUpdateProvider<T1> where T1 : class
|
||||
{
|
||||
public OdbcPostgreSQLInsertOrUpdate(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
|
||||
: base(orm, commonUtils, commonExpression)
|
||||
{
|
||||
}
|
||||
|
||||
public override string ToSql()
|
||||
{
|
||||
if (_source?.Any() != true) return null;
|
||||
|
||||
var insert = _orm.Insert<T1>()
|
||||
.AsTable(_tableRule).AsType(_table.Type)
|
||||
.WithConnection(_connection)
|
||||
.WithTransaction(_transaction)
|
||||
.NoneParameter(true) as Internal.CommonProvider.InsertProvider<T1>;
|
||||
insert._source = _source;
|
||||
var ocdu = new OdbcPostgreSQLOnConflictDoUpdate<T1>(insert);
|
||||
ocdu.IgnoreColumns(_table.Columns.Values.Where(a => a.Attribute.CanUpdate == false).Select(a => a.Attribute.Name).ToArray());
|
||||
if (_table.Columns.Values.Where(a => a.Attribute.IsPrimary == false && a.Attribute.CanUpdate == true).Any() == false)
|
||||
ocdu.DoNothing();
|
||||
var sql = ocdu.ToSql();
|
||||
_params = insert._params;
|
||||
return sql;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,207 @@
|
||||
using FreeSql.Aop;
|
||||
using FreeSql.Internal.Model;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FreeSql.Odbc.PostgreSQL
|
||||
{
|
||||
public class OdbcPostgreSQLOnConflictDoUpdate<T1> where T1 : class
|
||||
{
|
||||
internal OdbcPostgreSQLInsert<T1> _pgsqlInsert;
|
||||
internal OdbcPostgreSQLUpdate<T1> _pgsqlUpdatePriv;
|
||||
internal OdbcPostgreSQLUpdate<T1> _pgsqlUpdate => _pgsqlUpdatePriv ??
|
||||
(_pgsqlUpdatePriv = new OdbcPostgreSQLUpdate<T1>(_pgsqlInsert.InternalOrm, _pgsqlInsert.InternalCommonUtils, _pgsqlInsert.InternalCommonExpression, null) { InternalTableAlias = "EXCLUDED" }
|
||||
.NoneParameter().SetSource(_pgsqlInsert.InternalSource) as OdbcPostgreSQLUpdate<T1>);
|
||||
ColumnInfo[] _columns;
|
||||
bool _doNothing;
|
||||
|
||||
public OdbcPostgreSQLOnConflictDoUpdate(IInsert<T1> insert, Expression<Func<T1, object>> columns = null)
|
||||
{
|
||||
_pgsqlInsert = insert as OdbcPostgreSQLInsert<T1>;
|
||||
if (_pgsqlInsert == null) throw new Exception("OnConflictDoUpdate 是 FreeSql.Provider.Odbc/PostgreSQL 特有的功能");
|
||||
|
||||
if (columns != null)
|
||||
{
|
||||
var colsList = new List<ColumnInfo>();
|
||||
var cols = _pgsqlInsert.InternalCommonExpression.ExpressionSelectColumns_MemberAccess_New_NewArrayInit(null, columns?.Body, false, null).ToDictionary(a => a, a => true);
|
||||
foreach (var col in _pgsqlInsert.InternalTable.Columns.Values)
|
||||
if (cols.ContainsKey(col.Attribute.Name))
|
||||
colsList.Add(col);
|
||||
_columns = colsList.ToArray();
|
||||
}
|
||||
if (_columns == null || _columns.Any() == false)
|
||||
_columns = _pgsqlInsert.InternalTable.Primarys;
|
||||
if (_columns.Any() == false) throw new Exception("OnConflictDoUpdate 功能要求实体类必须设置 IsPrimary 属性");
|
||||
}
|
||||
|
||||
protected void ClearData()
|
||||
{
|
||||
_pgsqlInsert.InternalClearData();
|
||||
_pgsqlUpdatePriv = null;
|
||||
}
|
||||
|
||||
public OdbcPostgreSQLOnConflictDoUpdate<T1> IgnoreColumns(Expression<Func<T1, object>> columns)
|
||||
{
|
||||
_pgsqlUpdate.IgnoreColumns(columns);
|
||||
return this;
|
||||
}
|
||||
public OdbcPostgreSQLOnConflictDoUpdate<T1> UpdateColumns(Expression<Func<T1, object>> columns)
|
||||
{
|
||||
_pgsqlUpdate.UpdateColumns(columns);
|
||||
return this;
|
||||
}
|
||||
public OdbcPostgreSQLOnConflictDoUpdate<T1> IgnoreColumns(string[] columns)
|
||||
{
|
||||
_pgsqlUpdate.IgnoreColumns(columns);
|
||||
return this;
|
||||
}
|
||||
public OdbcPostgreSQLOnConflictDoUpdate<T1> UpdateColumns(string[] columns)
|
||||
{
|
||||
_pgsqlUpdate.UpdateColumns(columns);
|
||||
return this;
|
||||
}
|
||||
|
||||
public OdbcPostgreSQLOnConflictDoUpdate<T1> Set<TMember>(Expression<Func<T1, TMember>> column, TMember value)
|
||||
{
|
||||
_pgsqlUpdate.Set(column, value);
|
||||
return this;
|
||||
}
|
||||
//由于表达式解析问题,ON CONFLICT("id") DO UPDATE SET 需要指定表别名,如 Set(a => a.Clicks + 1) 解析会失败
|
||||
//暂时不开放这个功能,如有需要使用 SetRaw("click = t.click + 1") 替代该操作
|
||||
//public OnConflictDoUpdate<T1> Set<TMember>(Expression<Func<T1, TMember>> exp)
|
||||
//{
|
||||
// _pgsqlUpdate.Set(exp);
|
||||
// return this;
|
||||
//}
|
||||
public OdbcPostgreSQLOnConflictDoUpdate<T1> SetRaw(string sql)
|
||||
{
|
||||
_pgsqlUpdate.SetRaw(sql);
|
||||
return this;
|
||||
}
|
||||
|
||||
public OdbcPostgreSQLOnConflictDoUpdate<T1> DoNothing()
|
||||
{
|
||||
_doNothing = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public string ToSql()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.Append(_pgsqlInsert.ToSql()).Append("\r\nON CONFLICT(");
|
||||
for (var a = 0; a < _columns.Length; a++)
|
||||
{
|
||||
if (a > 0) sb.Append(", ");
|
||||
sb.Append(_pgsqlInsert.InternalCommonUtils.QuoteSqlName(_columns[a].Attribute.Name));
|
||||
}
|
||||
if (_doNothing)
|
||||
{
|
||||
sb.Append(") DO NOTHING");
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Append(") DO UPDATE SET\r\n");
|
||||
|
||||
var sbSetEmpty = _pgsqlUpdate.InternalSbSet.Length == 0;
|
||||
var sbSetIncrEmpty = _pgsqlUpdate.InternalSbSetIncr.Length == 0;
|
||||
if (sbSetEmpty == false || sbSetIncrEmpty == false)
|
||||
{
|
||||
if (sbSetEmpty == false) sb.Append(_pgsqlUpdate.InternalSbSet.ToString().Substring(2));
|
||||
if (sbSetIncrEmpty == false) sb.Append(sbSetEmpty ? _pgsqlUpdate.InternalSbSetIncr.ToString().Substring(2) : _pgsqlUpdate.InternalSbSetIncr.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
var colidx = 0;
|
||||
foreach (var col in _pgsqlInsert.InternalTable.Columns.Values)
|
||||
{
|
||||
if (col.Attribute.IsPrimary || _pgsqlUpdate.InternalIgnore.ContainsKey(col.Attribute.Name)) continue;
|
||||
|
||||
if (colidx > 0) sb.Append(", \r\n");
|
||||
|
||||
if (col.Attribute.IsVersion == true)
|
||||
{
|
||||
var field = _pgsqlInsert.InternalCommonUtils.QuoteSqlName(col.Attribute.Name);
|
||||
sb.Append(field).Append(" = ").Append(_pgsqlInsert.InternalCommonUtils.QuoteSqlName(_pgsqlInsert.InternalTable.DbName)).Append(".").Append(field).Append(" + 1");
|
||||
}
|
||||
else if (_pgsqlInsert.InternalIgnore.ContainsKey(col.Attribute.Name))
|
||||
{
|
||||
var caseWhen = _pgsqlUpdate.InternalWhereCaseSource(col.CsName, sqlval => sqlval).Trim();
|
||||
sb.Append(caseWhen);
|
||||
if (caseWhen.EndsWith(" END")) _pgsqlUpdate.InternalToSqlCaseWhenEnd(sb, col);
|
||||
}
|
||||
else
|
||||
{
|
||||
var field = _pgsqlInsert.InternalCommonUtils.QuoteSqlName(col.Attribute.Name);
|
||||
sb.Append(field).Append(" = EXCLUDED.").Append(field);
|
||||
}
|
||||
++colidx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public long ExecuteAffrows()
|
||||
{
|
||||
var sql = this.ToSql();
|
||||
if (string.IsNullOrEmpty(sql)) return 0;
|
||||
|
||||
var before = new CurdBeforeEventArgs(_pgsqlInsert.InternalTable.Type, _pgsqlInsert.InternalTable, CurdType.Insert, sql, _pgsqlInsert.InternalParams);
|
||||
_pgsqlInsert.InternalOrm.Aop.CurdBeforeHandler?.Invoke(_pgsqlInsert, before);
|
||||
long ret = 0;
|
||||
Exception exception = null;
|
||||
try
|
||||
{
|
||||
ret = _pgsqlInsert.InternalOrm.Ado.ExecuteNonQuery(_pgsqlInsert.InternalConnection, _pgsqlInsert.InternalTransaction, CommandType.Text, sql, _pgsqlInsert.InternalParams);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
exception = ex;
|
||||
throw ex;
|
||||
}
|
||||
finally
|
||||
{
|
||||
var after = new CurdAfterEventArgs(before, exception, ret);
|
||||
_pgsqlInsert.InternalOrm.Aop.CurdAfterHandler?.Invoke(_pgsqlInsert, after);
|
||||
ClearData();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if net40
|
||||
#else
|
||||
async public Task<long> ExecuteAffrowsAsync()
|
||||
{
|
||||
var sql = this.ToSql();
|
||||
if (string.IsNullOrEmpty(sql)) return 0;
|
||||
|
||||
var before = new CurdBeforeEventArgs(_pgsqlInsert.InternalTable.Type, _pgsqlInsert.InternalTable, CurdType.Insert, sql, _pgsqlInsert.InternalParams);
|
||||
_pgsqlInsert.InternalOrm.Aop.CurdBeforeHandler?.Invoke(_pgsqlInsert, before);
|
||||
long ret = 0;
|
||||
Exception exception = null;
|
||||
try
|
||||
{
|
||||
ret = await _pgsqlInsert.InternalOrm.Ado.ExecuteNonQueryAsync(_pgsqlInsert.InternalConnection, _pgsqlInsert.InternalTransaction, CommandType.Text, sql, _pgsqlInsert.InternalParams);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
exception = ex;
|
||||
throw ex;
|
||||
}
|
||||
finally
|
||||
{
|
||||
var after = new CurdAfterEventArgs(before, exception, ret);
|
||||
_pgsqlInsert.InternalOrm.Aop.CurdAfterHandler?.Invoke(_pgsqlInsert, after);
|
||||
ClearData();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
@ -18,6 +18,14 @@ namespace FreeSql.Odbc.PostgreSQL
|
||||
{
|
||||
}
|
||||
|
||||
internal string InternalTableAlias;
|
||||
internal StringBuilder InternalSbSet => _set;
|
||||
internal StringBuilder InternalSbSetIncr => _setIncr;
|
||||
internal Dictionary<string, bool> InternalIgnore => _ignore;
|
||||
internal void InternalResetSource(List<T1> source) => _source = source;
|
||||
internal string InternalWhereCaseSource(string CsName, Func<string, string> thenValue) => WhereCaseSource(CsName, thenValue);
|
||||
internal void InternalToSqlCaseWhenEnd(StringBuilder sb, ColumnInfo col) => ToSqlCaseWhenEnd(sb, col);
|
||||
|
||||
public override int ExecuteAffrows() => base.SplitExecuteAffrows(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
|
||||
public override List<T1> ExecuteUpdated() => base.SplitExecuteUpdated(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
|
||||
|
||||
@ -65,6 +73,7 @@ namespace FreeSql.Odbc.PostgreSQL
|
||||
if (_table.Primarys.Length == 1)
|
||||
{
|
||||
var pk = _table.Primarys.First();
|
||||
if (string.IsNullOrEmpty(InternalTableAlias) == false) caseWhen.Append(InternalTableAlias).Append(".");
|
||||
caseWhen.Append(_commonUtils.QuoteReadColumn(pk.CsType, pk.Attribute.MapType, _commonUtils.QuoteSqlName(pk.Attribute.Name)));
|
||||
return;
|
||||
}
|
||||
@ -73,6 +82,7 @@ namespace FreeSql.Odbc.PostgreSQL
|
||||
foreach (var pk in _table.Primarys)
|
||||
{
|
||||
if (pkidx > 0) caseWhen.Append(" || '+' || ");
|
||||
if (string.IsNullOrEmpty(InternalTableAlias) == false) caseWhen.Append(InternalTableAlias).Append(".");
|
||||
caseWhen.Append(_commonUtils.QuoteReadColumn(pk.CsType, pk.Attribute.MapType, _commonUtils.QuoteSqlName(pk.Attribute.Name))).Append("::varchar");
|
||||
++pkidx;
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ namespace FreeSql.Odbc.PostgreSQL
|
||||
public IUpdate<T1> Update<T1>(object dywhere) where T1 : class => new OdbcPostgreSQLUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
|
||||
public IDelete<T1> Delete<T1>() where T1 : class => new OdbcPostgreSQLDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, null);
|
||||
public IDelete<T1> Delete<T1>(object dywhere) where T1 : class => new OdbcPostgreSQLDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
|
||||
public IInsertOrUpdate<T1> InsertOrUpdate<T1>() where T1 : class => new OdbcPostgreSQLInsertOrUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression);
|
||||
|
||||
public IAdo Ado { get; }
|
||||
public IAop Aop { get; }
|
||||
|
@ -1,9 +1,7 @@
|
||||
using FreeSql.Internal;
|
||||
using FreeSql.Internal.ObjectPool;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
@ -0,0 +1,43 @@
|
||||
using FreeSql.Internal;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace FreeSql.Odbc.SqlServer
|
||||
{
|
||||
|
||||
class OdbcSqlServerInsertOrUpdate<T1> : Internal.CommonProvider.InsertOrUpdateProvider<T1> where T1 : class
|
||||
{
|
||||
public OdbcSqlServerInsertOrUpdate(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
|
||||
: base(orm, commonUtils, commonExpression)
|
||||
{
|
||||
}
|
||||
|
||||
public override string ToSql()
|
||||
{
|
||||
if (_source?.Any() != true) return null;
|
||||
if (_table.Primarys.Any() == false) throw new Exception($"InsertOrUpdate 功能要求实体类 {_table.CsName} 必须有主键");
|
||||
|
||||
var sb = new StringBuilder().Append("MERGE INTO ").Append(_commonUtils.QuoteSqlName(TableRuleInvoke())).Append(" t1 \r\n")
|
||||
.Append("USING (");
|
||||
WriteSourceSelectUnionAll(sb);
|
||||
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);
|
||||
if (cols.Any())
|
||||
sb.Append("WHEN MATCHED THEN \r\n")
|
||||
.Append(" update set ").Append(string.Join(", ", cols.Select(a =>
|
||||
a.Attribute.IsVersion ?
|
||||
$"{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} + 1" :
|
||||
$"{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{a.Attribute.Name}"
|
||||
))).Append(" \r\n");
|
||||
|
||||
cols = _table.Columns.Values;
|
||||
sb.Append("WHEN NOT MATCHED THEN \r\n")
|
||||
.Append(" insert (").Append(string.Join(", ", cols.Select(a => _commonUtils.QuoteSqlName(a.Attribute.Name)))).Append(") \r\n")
|
||||
.Append(" values (").Append(string.Join(", ", cols.Select(a => $"t2.{a.Attribute.Name}"))).Append(");");
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
@ -23,6 +23,7 @@ namespace FreeSql.Odbc.SqlServer
|
||||
public IUpdate<T1> Update<T1>(object dywhere) where T1 : class => new OdbcSqlServerUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
|
||||
public IDelete<T1> Delete<T1>() where T1 : class => new OdbcSqlServerDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, null);
|
||||
public IDelete<T1> Delete<T1>(object dywhere) where T1 : class => new OdbcSqlServerDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
|
||||
public IInsertOrUpdate<T1> InsertOrUpdate<T1>() where T1 : class => new OdbcSqlServerInsertOrUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression);
|
||||
|
||||
public IAdo Ado { get; }
|
||||
public IAop Aop { get; }
|
||||
|
Reference in New Issue
Block a user