0

I'm using Dapper for handling database connection in a .NET project. The automatic column mapping works well and I can also map columns to different property names in the model. However, how can I map computed properties? For example, my model is

class User
{
    public int Id {get; set;}
    public string Name {get; set;}
    public bool IsPremiumUser {get; set;}
}

And the table is

Id | Name | CreationDate | IsPremiumUser

Now, IsPremiumUser can be null in db but not in the model. I'd like it to be mapped by the following logic:

if (row.IsPremiumUser != null)
{
    model.IsPremiumUser = row.IsPremiumUser;
}
else
{
    model.IsPremiumUser = row.CreationDate < 1.1.2000;
}

In other words, its value depends on 2 columns. Also there are multiple cases where I'd like to set a boolean property based on if a certain relationship exists. How to handle these more complex mapping cases?

3
  • How this mapping should work when you will try to save an item back to database? if IsPremiumUser was null (when you read that), should it be updated and has a value? Commented Mar 15, 2017 at 11:51
  • Maybe you just need to and additional property that will be calculated but not mapped to db table? Commented Mar 15, 2017 at 11:52
  • Yes, that's exactly what I mean. Those computed values will not be saved back to db. Commented Mar 15, 2017 at 12:16

2 Answers 2

1

Just use SQL query which will check if IsPremiumUser field not null and return result of creation date check if user does not have this flag set:

var sql =
    @"SELECT 
        Id,
        Name,
        CASE
            WHEN IsPremiumUser IS NOT NULL
                THEN IsPremiumUser
                ELSE CAST(CASE WHEN CreationDate < '2000-01-01' THEN 1 ELSE 0 END AS BIT)
        END AS IsPremiumUser
        FROM Users";
var users = conn.Query<User>(sql);

Other option will be using dynamic query with manual mapping results to user class:

var sql = @"SELECT Id, Name, CreationDate, IsPremiumUser FROM Users";
var millenium = new DateTime(2000, 1, 1);

var users = conn.Query(sql).Select(row => new User {
       Id = row.Id,
       Name = row.Name,
       IsPremiumUser = row.IsPremiumUser == null
           ? row.CreationDate < millenium
           : row.IsPremiumUser
    });
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks, I ended up using this approach, although it's not exactly what I had in mind. What if I have some more complex mapping logic that is not convenient to do on the db side?
@eko please refresh page :) Keep in mind that Dapper will return IsPremiumUser flag either as null or as boolean. It will not return nullable boolean
0

Another option is to make a factory and let it assemble the user:

var userRecords = _connection.Query<UserRecord>("select * from users");   
var users = UserFactory.Build(userRecords);
  • UserRecord class is only used to query the data
  • Factory will handle property mapping and dynamic properties

Pros: Keep SQL queries free of logic. Factory is more flexible over time.

Cons: More code

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.