Richardissimo Richardissimo - 2 months ago 21
C# Question

C# change Dapper dynamic to complain if the property doesn't exist

We're using Dapper to fetch data from our SQL database, which returns our data as a collection of 'dynamic'. I understand the power of dynamic types, and the flexibility of "duck typing", basically "if it quacks like a duck, then it is a duck - I don't need to declare that it's a duck".

However, I don't understand why if I try to get a property from a dynamic object that it doesn't have, why doesn't it complain? For example, if I had something that wasn't a duck and I called "Quack" on it, I would have thought it reasonable to expect it to complain. EDIT: see comments, this seems to be something about the dynamic which Dapper is giving me because a standard dynamic object gives a runtime error if the property doesn't exist.

Is there a way I can make it complain?

The code that I have is a sequence of lines taking properties from the 'dynamic' and assigning them to the corresponding property in the strongly-typed object. The property names don't always tie-up (due to legacy database naming standards). At the moment, if a field name is misspelled on the dynamic, then it will just fail silently. I want it to complain. I don't want to have to rewrite each single line of code into 5 lines of "does [hard-coded name] property exist on the dynamic"/"if not complain"/"get the value and put it in the right place".

EDIT: Here is the specific code, in case that helps... the field name that is incorrect is "result.DecisionLevel", and I don't get a runtime error, it just assigns null into the target property

var results = _connection.Query("usp_sel_Solution", new { IdCase = caseId }, commandType: CommandType.StoredProcedure);
return results.Select(result => new Solution
{
IsDeleted = result.IsDeleted,
FriendlyName = result.FriendlyName,
DecisionLevel = (DecisionLevel?)result.DecisionLevel,
}).ToList();

Answer

You can add wrapping to source objects you have and implement the desired behavior in it (throwing or not trowing an exception, providing a default value or fixing the property names). Something like this:

public class WrapperDynamic : DynamicObject { private dynamic _source; public WrapperDynamic(dynamic source) { _source = source; }

public override bool TryGetMember(GetMemberBinder binder, out object result)
{                        
    if (_source.CheckTheProperyExist(binder))
    {
        result = _source.GetProperty(binder);
        return true;
    }
    return false;
}

}

You should implement CheckTheProperyExist and GetProperty depending on what kind of source objects.

They you should add covering to you selects

return results.Select(x=>new WrapperDynamic(x))
.Select(result => new Solution
        {
            IsDeleted = result.IsDeleted,
            FriendlyName = result.FriendlyName,
            DecisionLevel = (DecisionLevel?)result.DecisionLevel,
        }).ToList();

You can add name conversion for legacy names in this wrapper.

Comments