Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dapper does not warn or fail with missing data

Tags:

orm

c#-4.0

dapper

Let's say I have a class (simplistic for example) and I want to ensure that the PersonId and Name fields are 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 (i.e. throw an exception when not all the properties in the class are 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 the 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.

like image 775
AboutDev Avatar asked Feb 12 '13 23:02

AboutDev


1 Answers

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 it 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.

like image 91
Marc Gravell Avatar answered Nov 06 '22 15:11

Marc Gravell