tmsmith / Dapper-Extensions

Dapper Extensions is a small library that complements Dapper by adding basic CRUD operations (Get, Insert, Update, Delete) for your POCOs. For more advanced querying scenarios, Dapper Extensions provides a predicate system. The goal of this library is to keep your POCOs pure by not requiring any attributes or base class inheritance.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Update generates wrong SQL when running parallel

MitarNikolic opened this issue · comments

Hello everyone,

I created a XUnit test which uses DapperExtensions to update two different tables in the database.
This works perfectly fine as long as you execute the two updates one after another.
As soon as you try running them parallel, tho it generates the following exception:

System.Data.SqlClient.SqlException
Must declare the scalar variable "@u_2".

Looking at the SQL in the server profiler of "Microsoft SQL-Server management studio" you can see that wrong SQL gets generated.

Kind regards
Mitar

Any Updates for this?

I have the same issue,

After run this code:

await DbConnection.UpdateAsync(aggregateRoot, DbTransaction);

I got this is the exception:

'DbConnection.Update(aggregateRoot, DbTransaction)' threw an exception of type 'System.Data.SqlClient.SqlException' Class: 15 ClientConnectionId: {2e64d6d8-18eb-4c31-be0f-8d788125156b} Data: {System.Collections.ListDictionaryInternal} ErrorCode: -2146232060 Errors: {System.Data.SqlClient.SqlErrorCollection} HResult: -2146232060 HelpLink: null InnerException: null LineNumber: 1 Message: "Must declare the scalar variable \"@u_13\"." Number: 137 Procedure: "" Server: "REMOVED_FOR_SECURITY" Source: "Core .Net SqlClient Data Provider" StackTrace: "...."

Same as MitarNikolic, when I look at the SQL in the server profiler of "Microsoft SQL-Server management studio" you can see that wrong SQL gets generated.

FYI:
This only happens after migrate to:
"DapperExtensions" Version="1.7.0"
The exception is fixed for the prev version:
"DapperExtensions" Version="1.6.3"

But unfourtunally you get the warning:
Severity Code Description Project File Line Suppression State
Warning NU1701 Package 'DapperExtensions 1.6.3' was restored using '.NETFramework,Version=v4.6.1, .NETFramework,Version=v4.6.2, .NETFramework,Version=v4.7, .NETFramework,Version=v4.7.1, .NETFramework,Version=v4.7.2, .NETFramework,Version=v4.8' instead of the project target framework '.NETCoreApp,Version=v3.1'. This package may not be fully compatible with your project.

Hi @urodriguez , just to help me, did you try to use the Sync update?? I'm asking because the SQL Generation is the same for both of them and if one works and the other don't I'll have a more restricted area to look for.

Also it would help to send me the code example with the mappings

I didn't.
because using the sync update version is not performant for me.
thats why tried to use the async version on 1.7 but it didnt work.
however it worked for 1.6.3

@urodriguez I asked about the test not for performance but for helping me to find the issue. If the same happens in the sync version it's 1 thing... if only in asysnc its something else

Investigating this issue I could notice that version 1.6.3, even having a Async method always used the SYNC implementor.

I'm still looking to fix it but I really need information to find the issue.

This is the same as #306, and I have it as well. Below is a short program that causes the bug - at least on my machine in LinqPad, which throws with the message "Must declare the scalar variable "@u_3."

void Main()
{
        // Remember to run the sql at the bottom to create the tables
	var connectionString = "***INSERT CONNECTIONSTRING HERE***";
	var iterationCount = 50;

	Init();

	var task1 = Task.Run(() =>
	{
		var conn = new SqlConnection(connectionString);
		conn.Open();
		for (int i = 0; i < iterationCount; i++)
		{
			conn.Update(new TestA { Id = 1, Prop1 = 1, Prop2 = 2, Prop3 = 3 });
		}
	});

	var task2 = Task.Run(() =>
	{
		var conn = new SqlConnection(connectionString);
		conn.Open();
		for (int i = 0; i < iterationCount; i++)
		{
			conn.Update(new TestB { Id = 1, Prop1 = "1", Prop2 = "2" });
		}
	});

	Task.WaitAll(task1, task2);

	void Init()
	{
		var conn = new SqlConnection(connectionString);
		conn.Open();
		
		conn.Insert(new TestA { Prop1 = 1, Prop2 = 2, Prop3 = 3 });
		conn.Insert(new TestB { Prop1 = "1", Prop2 = "2" });
	}
}

public class TestA
{
	public long Id { get; set; }
	public long Prop1 { get; set; }
	public long Prop2 { get; set; }
	public long Prop3 { get; set; }
}

public class TestB
{
	public long Id { get; set; }
	public string? Prop1 { get; set; }
	public string? Prop2 { get; set; }
}

public class TestAMapper : ClassMapper<TestA>
{
	public TestAMapper()
	{
		Table("TestA");
		AutoMap();
	}
}

public class TestBMapper : ClassMapper<TestB>
{
	public TestBMapper()
	{
		Table("TestB");
		AutoMap();
	}
}
/*
create table dbo.TestA
(
    Id    int identity,
    Prop1 int,
    Prop2 int,
    Prop3 int
)
go


create table dbo.TestB
(
    Id    int identity,
    Prop1 nvarchar(50),
    Prop2 nvarchar(50)
)
go
*/