Dapper does not warn or fail with missing data

c#-4.0 dapper orm

Question

Let's say I have a class (simplistic for example) and I want to ensure that the PersonId and Name field is ALWAYS populated.

public class Person
{
    int PersonId { get; set; }
    string Name { get; set; }
    string Address { get; set; }
}

Currently my query would be

Person p = conn.Query<Person>("SELECT * FROM People");

However, I may have changed my database schema from PersonId to PID and now the code is going to go through just fine.

What I'd like to do is one of the following:

  1. Decorate the property PersonId with an attribute such as Required (that dapper can validate)

  2. Tell dapper to figure out that the mappings are not getting filled out completely (ie. throw an exception when all the properties in the class are not filled out by data from the query.)

Is this possible currently? If not, can someone point me to how I could do this without affecting performance too badly?

IMHO, the second option would be best because it won't break existing code for users and it doesn't require more attribute decoration on classes we may not have access to.

Expert Answer

At the moment, no this is not possible. And indeed, there are a lot of cases where it is actively useful to populate a partial model, so I wouldn't want to add anything implicit. In many cases, the domain model is an extended view on the data model, so I don't think option 2 can work - and I know it would break in a gazillion places in my code ;p If we restrict ourselves to the more explicit options...

So far, we have deliberately avoided things like attributes; the idea has been to keep is as lean and direct as possible. I'm not pathologically opposed to attributes - just: it can be problematic having to probe them. But maybe it is time... we could perhaps also allow simple column mapping at the same time, i.e.

[Map(Name = "Person Id", Required = true)]
int PersonId { get; set; }

where both Name and Required are optional. Thoughts? This is problematic in a few ways, though - in particular at the moment we only probe for columns we can see, in particular in the extensibility API.

The other possibility is an interface that we check for, allowing you to manually verify the data after loading; for example:

public class Person : IMapCallback {
    void IMapCallback.BeforePopulate() {}
    void IMapCallback.AfterPopulate() {
        if(PersonId == 0)
            throw new InvalidOperationException("PersonId not populated");
    }
}

The interface option makes me happier in many ways:

  • it avoids a lot of extra reflection probing (just one check to do)
  • it is more flexible - you can choose what is important to you
  • it doesn't impact the extensibility API

but: it is more manual.

I'm open to input, but I want to make sure we get it right rather than rush in all guns blazing.



Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why