12

This is my first experience with Dapper.Contrib (latest version from Nuget) and it's a strange situation:

using (SqlConnection cn = new SqlConnection(connectionString))
{
    cn.Open();
    var product = cn.Get<Product>(1);
}

On SqlMapperExtensions, it raises the error Invalid object name 'Products':

public static T Get<T>(this IDbConnection connection,
                       dynamic id, 
                       IDbTransaction transaction = null, 
                       int? commandTimeout = null) where T : class
{
    var type = typeof(T);
    string sql;
    if (!GetQueries.TryGetValue(type.TypeHandle, out sql))
}

The database receives the command select * from Products where Id = @id which is wrong.

Why does it append s to Product?

I've tried with other tables and get the same result.

Chris Marisic
  • 32,487
  • 24
  • 164
  • 258
nam vo
  • 3,271
  • 12
  • 49
  • 76

2 Answers2

19

It is desgined this way. You can override the default behavior by decorating your POCO classes with Dapper.Contrib.Extensions.TableAttribute.

using Dapper.Contrib.Extensions;

[Table("Product")]
public class Product
{
...
}
Kiquenet
  • 14,494
  • 35
  • 148
  • 243
Farzan Hajian
  • 1,799
  • 17
  • 27
  • 3
    Your answer is great, although it is not a good practice to have Dapper dependency on an assembly of POCO Dapper is happy if you do using System.ComponentModel.DataAnnotations.Schema; instead of using Dapper.Contrib.Extensions – Anand Oct 28 '17 at 03:25
10

It seems that it's written this way, you can check the source code

Or more specifically:

private static string GetTableName(Type type)
{
    //.... codes

    if (TableNameMapper != null)
    {
        name = TableNameMapper(type);
    }
    else
    {
        var tableAttr = //.... lookup attribute
        if (tableAttr != null)
            name = tableAttr.Name;
        else
        {
            name = type.Name + "s";
            if (type.IsInterface() && name.StartsWith("I"))
                    name = name.Substring(1);
        }
    }

If you want to use the literal type name you can easily configure this.

SqlMapperExtensions.TableNameMapper = (type) => {
    //use exact name
    return type.Name;
};
Chris Marisic
  • 32,487
  • 24
  • 164
  • 258
Dimitar Dimitrov
  • 14,868
  • 8
  • 51
  • 79