I'm converting a Visual Basic API to .NET 8 using the same SQL Server query with the same parameters, and I noticed that some rows are not being displayed in the response object.
The query uses UNION ALL and the missing rows only exist in the second SELECT statement (Deleted_Appointments table):
SELECT
A.Appointment_Id,
A.Appointment_Date,
C.Client_Id,
C.Name AS Client_Name,
S.Service_Id,
S.Description AS Service_Name,
CO.Name AS Company_Name,
CO.Address AS Company_Address,
'' AS Deleted_By
FROM Appointments A (NOLOCK)
LEFT JOIN Appointment_Services ApS (NOLOCK) ON ApS.Appointment_Id = A.Appointment_Id
LEFT JOIN Services S (NOLOCK) ON S.Service_Id = ApS.Service_Id
LEFT JOIN Clients C (NOLOCK) ON C.Client_Id = A.Client_Id
LEFT JOIN Companies CO (NOLOCK) ON CO.Company_Id = A.Company_Id
LEFT JOIN Users U (NOLOCK) ON U.Id = A.User_Id
WHERE A.Appointment_Date BETWEEN '07/01/2024 00:00:00' AND '07/31/2024 23:59:59'
UNION ALL
SELECT
DA.Appointment_Id,
DA.Appointment_Date,
C.Client_Id,
C.Name AS Client_Name,
S.Service_Id,
S.Description AS Service_Name,
CO.Name AS Company_Name,
CO.Address AS Company_Address,
U.Name AS Deleted_By
FROM Deleted_Appointments DA (NOLOCK)
LEFT JOIN Deleted_Appointment_Services DAS (NOLOCK) ON DAS.Appointment_Id = DA.Appointment_Id
LEFT JOIN Services S (NOLOCK) ON S.Service_Id = DAS.Service_Id
LEFT JOIN Clients C (NOLOCK) ON C.Client_Id = DA.Client_Id
LEFT JOIN Companies CO (NOLOCK) ON CO.Company_Id = DA.Company_Id
LEFT JOIN Users U (NOLOCK) ON U.Id = DA.User_Id
WHERE DA.Appointment_Date BETWEEN '07/01/2024 00:00:00' AND '07/31/2024 23:59:59'
The C# code using Dapper's QueryAsync to retrieve the data:
public async Task<List<AppointmentsResponse>> GetAppointments(
DateTime startDate,
DateTime endDate,
List<long> ClientIds,
int Status,
bool IsMobile
)
{
var sql = new StringBuilder();
sql.AppendLine(/* the above query */);
// These statements are repeated for the
// second SELECT statement with the correct
// table alias. I know... bad code. It will be fixed.
if (IsMobile)
sql.AppendLine("AND A.IsMobile = 1");
if (ClientIds.Count > 0)
{
string inClause = string.Join(", ", ClientIds);
sql.AppendLine($"AND A.Client_Id IN ({inClause})");
}
if (Status > 0)
sql.AppendLine($"AND A.Appointment_Status = {Status}");
using var con = connectionFactory.CreateConnection();
var result = await con.QueryAsync<AppointmentsResponse>(sql.ToString(), new { startDate, endDate });
return result.ToList();
}
I've tried using foreach to loop through each row and check if they were being returned correctly, and the missing rows are skipped entirely. I've also tried using QueryMultipleAsync but the result remained the same.
I've compared the same query with the one from the Visual Basic API and they both return the data as it should when executed in Microsoft's SSMS.
The VB implementation also returns it correctly.
EDIT: Added the complete query and C# parameters for better context.
20240701 00:00:00or2024-07-01T00:00:00. Oh, and instead of23:59:59for the end of the range, you should use an exclusive boundary (<instead of<=) for the start of the next day.SELECT * FROM ( SELECT ... FROM ... UNION ALL SELECT ... FROM ... ) tONfor the JOINs. This could be an oversite, but it could be more.StringBuilderfor an SQL query is a red flag for me. Are you building it dynamically, if so why? Can you not use proper parameters instead? If it's dynamic can you show the full code that builds it?