How to change the schema at runtime in Dapper-Extensions?

1.9k Views Asked by At

I am using Dapper Extensions but I have multiple schema names in My DB.

I found the an answer in below link but it assumes that I have only one schema name and this is not my case. Dapper Extensions Change Schema

What is the right way to change the schema name at the runtime?

1

There are 1 best solutions below

2
Kamil Budziewski On

Probably you won't use it anymore, but maybe there are more guys up there trying to figure it out.

I've been checking out how dapper works when running GetAll<> and Insert<>.

What it does:

var type = typeof(T);
var cacheType = typeof(List<T>);

if (!GetQueries.TryGetValue(cacheType.TypeHandle, out string sql))
{
    GetSingleKey<T>(nameof(GetAll));
    var name = GetTableName(type); <--- key thing

    sql = "select * from " + name;
    GetQueries[cacheType.TypeHandle] = sql;
}

So I've checked what GetTableName was doing:

private static string GetTableName(Type type)
{
    if (TypeTableName.TryGetValue(type.TypeHandle, out string name)) return name;

    if (TableNameMapper != null)
    {
        name = TableNameMapper(type); <-- key thing
    }
    else
    {
        //NOTE: This as dynamic trick should be able to handle both our own Table-attribute as well as the one in EntityFramework 
        var tableAttr = type
#if NETSTANDARD1_3
            .GetTypeInfo()
#endif
            .GetCustomAttributes(false).SingleOrDefault(attr => attr.GetType().Name == "TableAttribute") as dynamic;
        if (tableAttr != null)
        {
            name = tableAttr.Name;
        }
        else
        {
            name = type.Name + "s";
            if (type.IsInterface() && name.StartsWith("I"))
                name = name.Substring(1);
        }
    }

    TypeTableName[type.TypeHandle] = name;
    return name;
}

Solution:

So I thought I can implement my own table name mapper with code like this:

SqlMapperExtensions.TableNameMapper = DapperMapper.TableNameMapper();

And

public static SqlMapperExtensions.TableNameMapperDelegate TableNameMapper()
{
    return (type) =>
    {
        var has = Attribute.GetCustomAttribute(type, typeof(CastleTableAttribute));
        if (has != null)
        {
            return $"{ConfigurationProvider.Schema}.{type.Name}";
        }
        else
        {
            return type.Name;
        }
    };
}

With that name mapper you just need to mark your table with that.

[CastleTable]
class CubeTimestamps
{
    [ExplicitKey]
    public int cube_id { get; set; }
    public DateTime cube_timestamp { get; set; }
}

you can implement your name mapper to use [TableName] attribute also. Because my simple implementation hides this feature.

Enjoy :)