删除和插入事务仍导致违反c#
我一直在运行一个应用程序,刚刚查看了它产生的错误日志。由于主键冲突,我收到多个错误。看过执行该操作的源代码后,我无法理解为什么会发生这种情况 该应用程序是用C#on Dotnet Core编写的,不使用ORM框架,而是使用删除和插入事务仍导致违反c#,c#,sql,.net,database,C#,Sql,.net,Database,我一直在运行一个应用程序,刚刚查看了它产生的错误日志。由于主键冲突,我收到多个错误。看过执行该操作的源代码后,我无法理解为什么会发生这种情况 该应用程序是用C#on Dotnet Core编写的,不使用ORM框架,而是使用SqlObjects 该命令使用DbCommand事务更新表。正如我所说的,即使命令本身在使用更新的时间重新提交之前删除了条目,我也会遇到主键冲突。我似乎无法理解为什么会出现这种情况,特别是当SqlCommand应该是一个事务时 命令 _sqlObjectFactory.Get
SqlObjects
该命令使用DbCommand
事务更新表。正如我所说的,即使命令本身在使用更新的时间重新提交之前删除了条目,我也会遇到主键冲突。我似乎无法理解为什么会出现这种情况,特别是当SqlCommand应该是一个事务时
命令
_sqlObjectFactory.GetConnection()
.Using(connection =>
{
var command = connection.Command(
_sqlObjectFactory, "DELETE FROM pf_ServiceHeartbeat WHERE ServiceName = @ServiceName AND MachineName = @MachineName")
.AddParameter(_sqlObjectFactory, "@ServiceName", serviceName)
.AddParameter(_sqlObjectFactory, "@MachineName", machineName);
command.ExecuteNonQuery();
command.CommandText = "INSERT INTO pf_ServiceHeartbeat (ServiceName, MachineName, LastRun) VALUES (@ServiceName, @MachineName, @LastRun)";
command.AddParameter(_sqlObjectFactory, "@LastRun", lastRun);
command.ExecuteNonQuery();
});
错误日志
Error: 11/07/2017 12:50:20 - SqlException: Violation of PRIMARY KEY constraint 'PK_pf_ServiceHeartbeat'. Cannot insert duplicate key in object 'dbo.pf_ServiceHeartbeat'. The duplicate key value is (PopForums.Email.EmailApplicationService, MACHINENAME).
The statement has been terminated.
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, SqlDataReader ds)
at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite, String methodName)
at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
at PopForums.Data.Sql.Repositories.ServiceHeartbeatRepository.<>c__DisplayClass3_0.b__0(DbConnection connection) in E:\Projects\Forum\src\PopForums.Sql\Repositories\ServiceHeartbeatRepository.cs:line 40
at PopForums.Data.Sql.Extensions.Using(DbConnection connection, Action`1 action) in E:\Projects\Forum\src\PopForums.Sql\Extensions.cs:line 53
at PopForums.Data.Sql.Repositories.ServiceHeartbeatRepository.RecordHeartbeat1(String serviceName, String machineName, DateTime lastRun) in E:\Projects\Forum\src\PopForums.Sql\Repositories\ServiceHeartbeatRepository.cs:line 32
at PopForums.Services.ServiceHeartbeatService.Add(String serviceName, String machineName) in E:\Projects\Forum\src\PopForums\Services\ServiceHeartbeatService.cs:line 37
at PopForums.Services.ServiceHeartbeatService.RecordHeartbeat(String serviceName, String machineName) in E:\Projects\Forum\src\PopForums\Services\ServiceHeartbeatService.cs:line 25
at PopForums.Services.ApplicationServiceBase.Execute(Object sender) in E:\Projects\Forum\src\PopForums\Services\ApplicationServiceBase.cs:line 50
HelpLink.ProdName: Microsoft SQL Server
HelpLink.ProdVer: 13.00.4422
HelpLink.EvtSrc: MSSQLServer
HelpLink.EvtID: 2627
HelpLink.BaseHelpUrl: http://go.microsoft.com/fwlink
HelpLink.LinkId: 20476
我复制了你的情况,除了谷歌沉默的
SqlObjects
SQL Server 2017预览版,在Ubuntu 16.04上
CREATE TABLE test.dbo.pf_ServiceHeartbeat (
ServiceName nvarchar(256) NOT NULL,
MachineName nvarchar(256) NOT NULL,
LastRun datetime NOT NULL,
CONSTRAINT PK_pf_ServiceHeartbeat PRIMARY KEY (ServiceName,MachineName)
)
var scsb = new SqlConnectionStringBuilder();
scsb.Password="....";
scsb.UserID="sa";
scsb.DataSource="localhost";
scsb.InitialCatalog="test";
using(SqlConnection conn = new SqlConnection(scsb.ConnectionString))
{
conn.Open();
using(var tran=conn.BeginTransaction()) {
using(var comm = new SqlCommand("DELETE FROM pf_ServiceHeartbeat WHERE ServiceName = @ServiceName AND MachineName = @MachineName", conn, tran)) {
comm.Parameters.AddWithValue("@ServiceName", "PopForums.Email.EmailApplicationService");
comm.Parameters.AddWithValue("@MachineName", "MACHINENAME");
comm.ExecuteNonQuery();
comm.CommandText="INSERT INTO pf_ServiceHeartbeat (ServiceName, MachineName, LastRun) VALUES (@ServiceName, @MachineName, @LastRun)";
comm.Parameters.AddWithValue("@LastRun", DateTime.Now);
comm.ExecuteNonQuery();
}
tran.Commit();
}
}
项目(csproj)文件:
无论是否使用事务,每次运行都可以正常运行
因为我看不出与使用
SqlObjects
实现有什么不同,也许您应该尝试直接使用ADO.NET?导致错误的中间级别更少。共享表定义和PK\u pf\u ServiceHeartbeat的定义。没有这些信息,这只是猜测。“重复的键值是(PopForums.Email.EmailApplicationService,MACHINENAME)。”它说MACHINENAME是PK。检查表定义。为列MACHINENAME
选择一个唯一值。您插入的名称在此列中已经存在。@ARr0w应用程序正在同一台计算机上运行,因此delete语句应该已将其删除。是否应该?将参数重新应用于insert语句您尚未将主键设置为群集?如果您这样做了,会有什么不同吗?默认情况下,MSSQL会将主键创建为聚集索引<因此,代码>聚集
是多余的。在不使用的情况下尝试它,然后使用DBeaver检查它是聚集索引还是非聚集索引。不管怎样,它是有效的。
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Data.Common" Version="4.3.0" />
<PackageReference Include="System.Data.SqlClient" Version="4.3.1" />
</ItemGroup>
</Project>
var scsb = new SqlConnectionStringBuilder();
scsb.Password="....";
scsb.UserID="sa";
scsb.DataSource="localhost";
scsb.InitialCatalog="test";
using(SqlConnection conn = new SqlConnection(scsb.ConnectionString))
{
conn.Open();
using(var tran=conn.BeginTransaction()) {
using(var comm = new SqlCommand("DELETE FROM pf_ServiceHeartbeat WHERE ServiceName = @ServiceName AND MachineName = @MachineName", conn, tran)) {
comm.Parameters.AddWithValue("@ServiceName", "PopForums.Email.EmailApplicationService");
comm.Parameters.AddWithValue("@MachineName", "MACHINENAME");
comm.ExecuteNonQuery();
comm.CommandText="INSERT INTO pf_ServiceHeartbeat (ServiceName, MachineName, LastRun) VALUES (@ServiceName, @MachineName, @LastRun)";
comm.Parameters.AddWithValue("@LastRun", DateTime.Now);
comm.ExecuteNonQuery();
}
tran.Commit();
}
}