Reputation: 363
As the title says, is there a way to check if a certain column has the concurrency check attribute or not?
To be more precisely, I am trying to compare current values with database values and I need to know which columns are different but ignoring the concurrency check column. Verifying the type is not an option because I use Oracle where the concurrency check is not byte[]
but is a numeric column updated by trigger and mapped to decimal
in my class.
I found here a way to get the columns and check which are/is primary key, but it looks like EdmScalarPropertyAttribute
only knows about EntityKey
and IsNullable
. So my question again: is there a way to do a similar thing for ConcurencyCheck column?
Thank you in advance.
Upvotes: 0
Views: 1502
Reputation: 22595
I have a class containing extension methods that lets me read data annotations like this:
int maxRefLen = ReflectionAPI.GetProperty<Organisation, String>(x => x.Name)
.GetAttribute<StringLengthAttribute>()
.GetValueOrDefault(x => x.MaximumLength, 256);
So to retrieve the ConcurrencyCheckAttribute
you should be able to do it like this:
var attr = ReflectionAPI.GetProperty<User, String>(x => x.Name)
.GetAttribute<ConcurrencyCheckAttribute>();
Here is the ReflectionAPI class:
Please note that the class includes part of a hack that @JonSkeet posted and described as "evil". I personally think this bit ain't so bad, but you should read the following references:
Override a generic method for value types and reference types.
Evil code - overload resolution workaround
public static class ReflectionAPI
{
public static int GetValueOrDefault<TInput>(this TInput a, Func<TInput, int> func, int defaultValue)
where TInput : Attribute
//Have to restrict to struct or you get the error:
//The type 'R' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'System.Nullable<T>'
{
if (a == null)
return defaultValue;
return func(a);
}
public static Nullable<TResult> GetValueOrDefault<TInput, TResult>(this TInput a, Func<TInput, TResult> func, Nullable<TResult> defaultValue)
where TInput : Attribute
where TResult : struct
//Have to restrict to struct or you get the error:
//The type 'R' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'System.Nullable<T>'
{
if (a == null)
return defaultValue;
return func(a);
}
//In order to constrain to a class without interfering with the overload that has a generic struct constraint
//we need to add a parameter to the signature that is a reference type restricted to a class
public class ClassConstraintHack<T> where T : class { }
//The hack means we have an unused parameter in the signature
//http://msmvps.com/blogs/jon_skeet/archive/2010/11/02/evil-code-overload-resolution-workaround.aspx
public static TResult GetValueOrDefault<TInput, TResult>(this TInput a, Func<TInput, TResult> func, TResult defaultValue, ClassConstraintHack<TResult> ignored = default(ClassConstraintHack<TResult>))
where TInput : Attribute
where TResult : class
{
if (a == null)
return defaultValue;
return func(a);
}
//I don't go so far as to use the inheritance trick decribed in the evil code overload resolution blog,
//just create some overloads that take nullable types - and I will just keep adding overloads for other nullable type
public static bool? GetValueOrDefault<TInput>(this TInput a, Func<TInput, bool?> func, bool? defaultValue)
where TInput : Attribute
{
if (a == null)
return defaultValue;
return func(a);
}
public static int? GetValueOrDefault<TInput>(this TInput a, Func<TInput, int?> func, int? defaultValue)
where TInput : Attribute
{
if (a == null)
return defaultValue;
return func(a);
}
public static T GetAttribute<T>(this PropertyInfo p) where T : Attribute
{
if (p == null)
return null;
return p.GetCustomAttributes(false).OfType<T>().LastOrDefault();
}
public static PropertyInfo GetProperty<T, R>(Expression<Func<T, R>> expression)
{
if (expression == null)
return null;
MemberExpression memberExpression = expression.Body as MemberExpression;
if (memberExpression == null)
return null;
return memberExpression.Member as PropertyInfo;
}
}
Upvotes: 0
Reputation: 363
Ok, I got it:
var properties = from p in
(from x in typeof(User).GetProperties()
select new{Name = x.Name, Attributes = x.GetCustomAttributes(false)})
where p.Attributes.Any(t => t is ConcurrencyCheckAttribute)
select p;
I wrote it like this because I also want the property name. Removing the where clause will give all properties and their custom attributes (including column name).
Upvotes: 2