-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
Description
We're about ready to rip Dapper out of everything... Everything worked great when we did the initial development but over the past year we have had numerous times when for no apparent reason it just starts incorrectly mapping SQL columns to the POCO properties. It seems to most often be when there is an "Id" column and another column that contains the word "Id" (i.e. "SurveyId"). It also seems to be related to the query having a JOIN despite that no columns from the join are SELECTed. I really hope someone can help us figure out what we're doing wrong because I'd hate to stop using Dapper but this unpredictable behavior is unacceptable. Here's the current example...
[DataContract]
public class ClientSurvey
{
[DataMember(EmitDefaultValue = false)]
public int Id { get; set; }
[DataMember]
public int ClientId { get; set; }
[DataMember(EmitDefaultValue = false)]
public int SurveyId { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public DateTime StartDate { get; set; }
[DataMember]
public DateTime? EndDate { get; set; }
[DataMember]
public bool IsPatientDefault { get; set; }
[DataMember]
public bool IsLocked { get; set; }
[DataMember]
public Survey Survey { get; set; }
[DataMember]
public string IntroHtml { get; set; }
[DataMember]
public string OutroHtml { get; set; }
[DataMember]
public int MaxResponses { get; set; }
}...
public async Task<ClientSurvey> GetDefaultAsync(int clientId)
{
// NOTE: This was actually "select cs.*" but has been spelled out for better understanding and to see if it would help with the mapping. It did not.
const string sql =
@"select cs.[Id], cs.[ClientId], cs.[SurveyId], cs.[Name], cs.[StartDate], cs.[EndDate], cs.[IsPatientDefault], cs.[ClientSurveyBundleId], cs.[IsLocked], cs.[IntroHtml], cs.[OutroHtml], cs.[MaxResponses], cs.[Description]
from dbo.ClientSurveys cs
inner join dbo.Surveys s on s.Id = cs.SurveyId
where cs.ClientId = @clientId
and cs.IsPatientDefault = 1
and isnull(cs.EndDate, '9999-1-1') > getdate()
and isnull(cs.StartDate, '2000-1-1') < getdate()
and s.IsActive = 1;";
using (var cnn = await OpenConnectionAsync())
{
var surveys = (await cnn.QueryAsync<ClientSurvey>(sql, new {ClientId = clientId})).ToList();
if (!surveys.Any())
{
return null;
}
if (surveys.Count() > 1)
{
throw new Exception("Multiple default surveys for client " + clientId);
}
var clientSurvey = surveys.First();
clientSurvey.Survey = await SurveysData.Instance.GetAsync(clientSurvey.SurveyId, clientSurvey.ClientId);
clientSurvey.SurveyId = 0; // Clear this so it doesn't serialize out and duplicate the data.
await ReplaceVariables(clientSurvey);
return clientSurvey;
}
}If this SQL is called in SSMS, I get back (among other things...): Id = 3, SurveyId = 2
However, if I call the function above then it assigns: clientSurvey.Id = 2, clientSurvey.SurveyId = 2
(note that there is not a record in the database where ClientSurvey.Id = 2)
So far we've managed to do weird things like changing or removing JOINs in exchange for less desirable queries just to force Dapper to get the mapping correct but this now seems to be an almost daily problem. Is anyone else experiencing this?
Our databases are Azure Database (v12) and our code is running in an Azure Website running .NET 4.5.2.
Thanks for any help you can offer. This is an urgent problem for us.
Ian