Based on Firos answer I solved the problem. However, I didn't quite like the syntax to be used and the fact that I would have to create a new class for the default values for each entity.
The syntax I got now looks like this:
mapping.ConstantValue(0).Column(@"client_id");
// or
mapping.ConstantValue(0, @"client_id");
I created the following extension methods for it:
public static PropertyPart
ConstantValue<TType, TValue>(this ClasslikeMapBase<TType> map, TValue value)
{
var getter =
new ConstantValueGetter<TValue>(CreateUniqueMemberName(), value);
ConstantValueAccessor.RegisterGetter(typeof(TType), getter);
var propertyInfo =
new GetterSetterPropertyInfo(typeof(TType), typeof(TValue),
getter.PropertyName, getter.Method, null);
var parameter = Expression.Parameter(typeof(TType), "x");
Expression body = Expression.Property(parameter, propertyInfo);
body = Expression.Convert(body, , typeof(object));
var lambda = Expression.Lambda<Func<TType, object>>(body, parameter);
return map.Map(lambda).Access.Using<ConstantValueAccessor>();
}
public static PropertyPart
ConstantValue<TType, TValue>(this ClasslikeMapBase<TType> map,
TValue value, string column)
{
return map.ConstantValue(value).Column(column);
}
The important differences are:
The first of those extension methods returns a PropertyPart
and has to be used in conjunction with the Column
method to specify which column the constant value should be mapped to. Because of this, the column name is not known when the extension method is executed and we need to create one ourselves. This is done by CreateUniqueMemberName
:
private static string CreateUniqueMemberName()
{
return "Dummy" + Guid.NewGuid().ToString("N");
}
Because you can only specify a type as access strategy and not an instance, I couldn't create an IPropertyAccessor
implementation allowed me to simply pass an IGetter
instance in the constructor. That's what ConstantValueAccessor.RegisterGetter(typeof(TType), getter);
solves. ConstantValueAccessor
has a static collection of getters:
internal class ConstantValueAccessor : IPropertyAccessor
{
private static readonly
ConcurrentDictionary<Type, SynchronizedCollection<IGetter>> _getters =
new ConcurrentDictionary<Type, SynchronizedCollection<IGetter>>();
public static void RegisterGetter(Type type, IGetter getter)
{
var getters =
_getters.GetOrAdd(type,
t => new SynchronizedCollection<IGetter>());
getters.Add(getter);
}
public IGetter GetGetter(Type theClass, string propertyName)
{
SynchronizedCollection<IGetter> getters;
if (!_getters.TryGetValue(theClass, out getters))
return null;
return getters.SingleOrDefault(x => x.PropertyName == propertyName);
}
// ...
}
The implementation of ConstantValueGetter<T>
is the same as the one from the provided link.
Because it wasn't that much fun to implement GetterSetterPropertyInfo
, here it is. One important difference is, that this implementation doesn't have any dependencies on (Fluent) NHibernate.