Dapper.Contrib Suggest to add InsertOrUpdate Functions
Nobody has claimed this yet.
Assessment
- Difficulty
- 5/5
- Estimated time
- Over a week
- Newbie friendliness
- 25/100
Research direction
The proposal references ITransaction.CommitTransaction and the external SqlBulkTools library, but names no repository files or tests. Start by locating the transaction implementation and comparing the referenced Insert, Update, and Delete behavior. Define the public API and expected matching, deletion, identity, and transaction semantics; done requires tests for those cases.
Written by the indexing model from the issue text.
Description
It is recommended to refer to this library to join InsertOrUpdate Functions https://github.com/olegil/SqlBulkTools
I can pass in an entity for automatic comparison Insert Update Delete Operation
void ITransaction.CommitTransaction(string connectionName, SqlCredential credentials, SqlConnection connection)
{
if (!_list.Any())
{
return;
}
if (_disableAllIndexes && (_disableIndexList != null && _disableIndexList.Any()))
{
throw new InvalidOperationException("Invalid setup. If \'TmpDisableAllNonClusteredIndexes\' is invoked, you can not use the \'AddTmpDisableNonClusteredIndex\' method.");
}
if (_matchTargetOn.Count == 0)
{
throw new InvalidOperationException("MatchTargetOn list is empty when it's required for this operation. " +
"This is usually the primary key of your table but can also be more than one column depending on your business rules.");
}
DataTable dt = _helper.ToDataTable(_list, _columns, _customColumnMappings, _matchTargetOn, _outputIdentity, _outputIdentityDic);
// Must be after ToDataTable is called.
_helper.DoColumnMappings(_customColumnMappings, _columns, _matchTargetOn);
using (SqlConnection conn = _helper.GetSqlConnection(connectionName, credentials, connection))
{
conn.Open();
var dtCols = _helper.GetDatabaseSchema(conn, _schema, _tableName);
using (SqlTransaction transaction = conn.BeginTransaction())
{
try
{
SqlCommand command = conn.CreateCommand();
command.Connection = conn;
command.Transaction = transaction;
command.CommandTimeout = _sqlTimeout;
//Creating temp table on database
command.CommandText = _helper.BuildCreateTempTable(_columns, dtCols, _outputIdentity);
command.ExecuteNonQuery();
_helper.InsertToTmpTable(conn, transaction, dt, _bulkCopyEnableStreaming, _bulkCopyBatchSize,
_bulkCopyNotifyAfter, _bulkCopyTimeout, _sqlBulkCopyOptions);
if (_disableIndexList != null && _disableIndexList.Any())
{
command.CommandText = _helper.GetIndexManagementCmd(IndexOperation.Disable, _tableName, _disableIndexList, _disableAllIndexes);
command.ExecuteNonQuery();
}
//if (_outputIdentity)
//{
// command.CommandText = _helper.GetOutputCreateTableCmd(_outputIdentity, "#TmpOutput",
// OperationType.Insert);
// command.ExecuteNonQuery();
//}
string comm =
_helper.GetOutputCreateTableCmd(_outputIdentity, "#TmpOutput", OperationType.Insert) +
"MERGE INTO " + _helper.GetFullQualifyingTableName(conn.Database, _schema, _tableName) +
" WITH (HOLDLOCK) AS Target " +
"USING #TmpTable AS Source " +
_helper.BuildJoinConditionsForUpdateOrInsert(_matchTargetOn.ToArray(),
_sourceAlias, _targetAlias) +
"WHEN MATCHED THEN " +
_helper.BuildUpdateSet(_columns, _sourceAlias, _targetAlias, _identityColumn) +
"WHEN NOT MATCHED BY TARGET THEN " +
_helper.BuildInsertSet(_columns, _sourceAlias, _identityColumn) +
(_deleteWhenNotMatchedFlag ? " WHEN NOT MATCHED BY SOURCE THEN DELETE " : " ") +
_helper.GetOutputIdentityCmd(_identityColumn, _outputIdentity, "#TmpOutput",
OperationType.Insert) +
"DROP TABLE #TmpTable;";
command.CommandText = comm;
command.ExecuteNonQuery();
if (_disableIndexList != null && _disableIndexList.Any())
{
command.CommandText = _helper.GetIndexManagementCmd(IndexOperation.Rebuild, _tableName, _disableIndexList);
command.ExecuteNonQuery();
}
if (_outputIdentity)
{
command.CommandText = "SELECT InternalId, Id FROM #TmpOutput;";
using (SqlDataReader reader = command.ExecuteReader())
{
var list = _list.ToList();
while (reader.Read())
{
var test = reader[0];
var test2 = reader[1];
T item;
if (_outputIdentityDic.TryGetValue((int)reader[0], out item))
{
Type type = item.GetType();
PropertyInfo prop = type.GetProperty(_identityColumn);
prop.SetValue(item, reader[1], null);
}
}
}
}
transaction.Commit();
}
catch (SqlException e)
{
for (int i = 0; i < e.Errors.Count; i++)
{
// Error 8102 is identity error.
if (e.Errors[i].Number == 8102)
{
// Expensive call but neccessary to inform user of an important configuration setup.
throw new IdentityException(e.Errors[i].Message);
}
}
transaction.Rollback();
throw;
}
catch (Exception)
{
transaction.Rollback();
throw;
}
finally
{
conn.Close();
}
}
}
}
- Dominant language
- C#
- Stars
- 293
- Forks
- 109
- PR merge metrics
- No merged PRs in 30d
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from DapperLib/Dapper.Contrib
-
Difficulty 1/5 Under an hour Newbie friendliness 75/100
DapperLib/Dapper.Contrib#22 · 2 comments ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 42/100
DapperLib/Dapper.Contrib#174 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 45/100
DapperLib/Dapper.Contrib#173 ·
-
Difficulty 1/5 Under an hour Newbie friendliness 10/100
DapperLib/Dapper.Contrib#172 · 1 comment · 4 reactions ·
-
Difficulty 3/5 1-2 days Newbie friendliness 48/100
DapperLib/Dapper.Contrib#169 ·
All issues in DapperLib/Dapper.Contrib
Similar issues
-
[Feat] 조합 영역 구분선 개선 Open
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
-
type/automation type/tech-debt
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
-
t/bug
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
-
ci-failure-cause test-failure
Difficulty 2/5 1-3 hours Newbie friendliness 82/100