UniqueAttribute that validates a unique field against its fellow rows in the database (inherits DataAnnotations.ValidationAttribute)

UPDATE: Jan 30 2012: Added check that entity is not itself (i.e. when user attempts to save the same entity).UPDATE: Feb 26 2012: Added support for inherited entities, where the validated property is on the sub-class of the inheritance hierarchy. Here is a ValidationAttribute subclass that will allow you to validate that a column doesn't have duplicates. It's intended to be used with EF 4.1 DbContext, or with the EF4's ObjectContext.namespace System.ComponentModel.DataAnnotations { #if !SILVERLIGHT   using System;   using System.Data.Entity;   using System.Data.Entity.Infrastructure;   using System.Data.Metadata.Edm;   using System.Data.Objects;   using System.Linq; #endif   /// <summary>   /// Validates whether a value is set in another row at the same column.   /// Does not validate null empty or whitespace strings.   /// </summary>      public class UniqueAttribute : ValidationAttribute   { #if SILVERLIGHT        /// <summary>     /// Just a body method, the ValidationAttribute requires the IsValid method to be overridden.     /// </summary>     protected override ValidationResult IsValid(object value, ValidationContext validationContext)     {       return ValidationResult.Success;     } #else     private readonly Type _ContextType;     public Type ContextType     {       get       {         return _ContextType;       }     }     //TODO: If placed in your domain, uncomment and replace MyDbContext with your domain's DbContext/ObjectContext class.     //public UniqueAttribute() : this(typeof(MyDbContext)) { }     /// <summary>     /// Initializes a new instance of <see cref="UniqueAttribute"/>.     /// </summary>     /// <param name="contextType">The type of <see cref="DbContext"/> or <see cref="ObjectContext"/> subclass that will be used to search for duplicates.</param>     public UniqueAttribute(Type contextType)     {       if (contextType == null)         throw new ArgumentNullException("contextType");       if (!contextType.IsSubclassOf(typeof(DbContext)) && !contextType.IsSubclassOf(typeof(ObjectContext)))         throw new ArgumentException("The contextType Type must be a subclass of DbContext or ObjectContext.", "contextType");       if (contextType.GetConstructor(Type.EmptyTypes) == null)         throw new ArgumentException("The contextType type must declare a public parameterless consructor.");       _ContextType = contextType;     }     /// <summary>     /// Validates the value against the matching columns in the other rows of this table.     /// Note that this method does not validate null or empty strings.     /// </summary>     /// <param name="value">The value to validate</param>     /// <param name="validationContext">The context information about the validation operation.</param>     /// <returns>An instance of the <see cref="ValidationResult"/> class.</returns>     protected override ValidationResult IsValid(object value, ValidationContext validationContext)     {       if (value == null || (value is string && string.IsNullOrWhiteSpace((string)value))) return ValidationResult.Success;       var type = validationContext.ObjectType;       var property = type.GetProperty(validationContext.MemberName);       type = property.DeclaringType;       using (var dbcontext = (IDisposable)Activator.CreateInstance(_ContextType))       {         var context = dbcontext is DbContext ? ((IObjectContextAdapter)dbcontext).ObjectContext : (ObjectContext)dbcontext;         var md = context.MetadataWorkspace;         var entityType = md.GetItems<EntityType>(DataSpace.CSpace).SingleOrDefault(et => et.Name == type.Name);         while (entityType.BaseType != null)           entityType = (EntityType)entityType.BaseType;         var objectType = typeof(object);         var isInherited = false;         var baseType = type;         while (baseType.Name != entityType.Name && baseType.BaseType != objectType)         {           baseType = baseType.BaseType;           isInherited = true;         }         var methodCreateObjectSet = typeof(ObjectContext).GetMethod("CreateObjectSet", Type.EmptyTypes).MakeGenericMethod(baseType);         var baseObjectSet = (ObjectQuery)methodCreateObjectSet.Invoke(context, new object { });         var objectSet = baseObjectSet;         var setType = baseObjectSet.GetType();         if (isInherited)         {           var ofType = setType.GetMethod("OfType");           ofType = ofType.MakeGenericMethod(type);           objectSet = (ObjectQuery)ofType.Invoke(baseObjectSet, null);           setType = objectSet.GetType();         }         var methodWhere = setType.GetMethod("Where");         var eSql = string.Format("it.{0} = @{0}", validationContext.MemberName);         var query = (ObjectQuery)methodWhere.Invoke(objectSet,           new object { eSql, new { new ObjectParameter(validationContext.MemberName, value) } });         var result = query.Execute(MergeOption.NoTracking).Cast<object>();         bool isValid = true;         using (var enumerator = result.GetEnumerator())         {           if (enumerator.MoveNext())           {             var nameProperty = typeof(ObjectSet<>).MakeGenericType(baseType).GetProperty("EntitySet");             var entitySet = (EntitySet)nameProperty.GetValue(baseObjectSet, null);             var entitySetName = entitySet.Name;             do             {               var current = enumerator.Current;               var curKey = context.CreateEntityKey(entitySetName, current);               var validatingKey = context.CreateEntityKey(entitySetName, validationContext.ObjectInstance);               if (curKey != validatingKey)               {                 isValid = false;                 break;               }             } while (enumerator.MoveNext());           }         }         return isValid ?           ValidationResult.Success :           new ValidationResult(             string.Format("There is already a '{0}' record that has its '{1}' field set to '{2}'.",               validationContext.ObjectType.Name,               validationContext.DisplayName,               value),             new { validationContext.MemberName });       }     } #endif   } }  As soon as you will be trying to call DbContext.SaveChanges in the...

Determine if char is Hebrew

19/01/2012

Simple Ex. method:// avoid unicode chars in code private const char FirstHebChar = (char)1488; //א private const char LastHebChar = (char)1514; //ת  private static bool IsHebrew(this char c) {   return c >= FirstHebChar && c <= LastHebChar; }Note: a comment bellow noted that the above function solely checks for hebrew characters within the א-ת range,it won't include punctuation marks, vowels or other biblical symbols.For a function that covers all (all that I'm aware of) Hebrew characters, please refer here.
one comment

Enum.IsDefined for combined values not declared in the enum body

12/01/2012

When you try to determine if an Enum value is defined in an Enum, it returns true only if the flags you've combined are explicitly declared in the Enum. Consider this Enum:// Enum defined with a FlagsAttribute attribute. enum Hue : sbyte {   Black = 0, //no color   Red = 1,   Green = 2,   Blue = 4,   Cyan = Green | Blue,//6   Magenta = Red | Blue,//5   BadColor = 127 } The following line will return false:var white = Hue.Red | Hue.Blue | Hue.Green; //7 Even tho theoretically the enum combination is valid. So to make sure a value doesn't exceed the enums limit, but is not necessarily declared, we can use the following function: (You can cashe the Enum.GetValues to improve performance)public static bool IsDefined(this Enum value) {   dynamic dyn = value;   var max = Enum.GetValues(value.GetType()).Cast<dynamic>().     Aggregate((e1, e2) => e1 | e2);   return (max & dyn) == dyn; } The above function will solve the problem:    static void Main(string args)     {       var white = Hue.Red | Hue.Blue | Hue.Green; //7       var isDef1 = Enum.IsDefined(typeof(Enum), white); //false       var isDef2 = white.IsDefined(); //true     } Note: Performance not tested at all.
tags: ,
no comments