2009-07-24 3 views
0

Я пытаюсь запустить этот общий DuplicateValidationRule, который в основном проверяет коллекцию для дубликатов (на основе общего типа бизнес-объекта, переданного в). Давайте принимать IBankAccount Бизнес-объект, например:Generic DuplicateValidationRule (проверка бизнес-объектов для дубликатов)

public interface IBankAccount : IMyBusinessObjectBase 
{ 
    IBank Bank 
    { 
     get; 
     set; 
    } 

    IBankAccountType BankAccountType 
    { 
     get; 
     set; 
    } 

    string AccountName 
    { 
     get; 
     set; 
    } 

    string AccountNumber 
    { 
     get; 
     set; 
    } 

    DateTime EffectiveDate 
    { 
     get; 
     set; 
    } 
} 

Допустим, у меня есть следующий набор IBankAccount

IBankAccount acc1 = new BankAccount(); 
acc1.AccountName = "Account1"; 
acc1.AccountNumber = "123456"; 
acc1.Bank = FetchBusinessObjectByID(1); //Fetch Bank 1 

IBankAccount acc2 = new BankAccount(); 
acc2.AccountName = "Account2"; 
acc2.AccountNumber = "654321"; 
acc2.Bank = FetchBusinessObjectByID(1); //Fetch Bank 1 

IBankAccount acc3 = new BankAccount(); 
acc3.AccountName = "Account3"; 
acc3.AccountNumber = "123456"; 
acc3.Bank = FetchBusinessObjectByID(2); //Fetch Bank 2 

IBankAccount acc4 = new BankAccount(); 
acc4.AccountName = "Account3"; 
acc4.AccountNumber = "123456"; 
acc4.Bank = FetchBusinessObjectByID(1); //Fetch Bank 2 

ICollection<IBankAccount> bankAccounts = new List<IBankAccount>(); 
bankAccount.Add(acc1); 
bankAccount.Add(acc2); 
bankAccount.Add(acc2); 
bankAccount.Add(acc4); 

Параметры:

T = BusinessObject Тип класса (Person, адрес, ВагЛАссоипЬ, Bank, BankBranch и т. Д.) String [] entityPropertyName = Массив свойств, которые нужно включить при проверке дубликатов.

Теперь позвольте использовать следующий сценарий: Предположим, я хочу проверить дубликаты BankAccounts, проверив номер счета и банк. Номер счета уникален в банке, но может существовать в другом банке. Поэтому, если вы посмотрите на список выше, то действуют Acc1, Acc2 и Acc3. Acc4 недействителен, поскольку этот номер счета для этого банка уже существует.

Итак, вызов для проверки будет выглядеть следующим образом.

DuplicateValidationRule.Validate (newBankAccountEntry, new string [] {"AccountNumber", "Bank.Name"});

Приведенный выше код передается в бизнес-сущности для проверки дубликатов и массива свойств, который включает в себя свойства, которые необходимо проверить.

public ValidationError Validate<T>(T entityProperty, string[] entityPropertyName) 
    {   
     ICollection<T> businessObjectList = FetchObjectsByType<T>(); 

     bool res = true; 
     for (int i = 0; i < entityPropertyName.Length; i++) 
     { 
      object value = getPropertyValue(entityProperty, entityPropertyName[i]); 

//By Using reflection and the getPropertyValue method I can substitute the properties to //compare. 
      if (businessObjectList.Any(x => getPropertyValue(x, entityPropertyName[i]).Equals(value) && 
             x.GetType().GetProperty("ID").GetValue(x,null).ToString()           
             != ((IBusinessObjectBase)entityProperty).ID.ToString())) 
       res &= true; 
      else 
       res &= false;    
     } 

     if (res) 
      return new ValidationError(_DuplicateMessage); 
     else 
      return ValidationError.Empty; 
    } 

Этот метод используется, чтобы получить реальный объект, чтобы проверить дубликаты на:

private static object getPropertyValue(object obj, string propertyName) 
    { 
     string[] PropertyNames = propertyName.Split('.'); 

     object propertyValue = obj; 

     for (int i = 0; i < PropertyNames.Length; i++) 
     { 
      propertyValue = propertyValue.GetType().GetProperty(PropertyNames[i], BindingFlags.Public | 
        BindingFlags.Instance | BindingFlags.Static | BindingFlags.FlattenHierarchy). 
        GetValue(propertyValue, null); 
     } 

     if (propertyValue.GetType() == typeof(string)) 
      return propertyValue.ToString().ToLower(CultureInfo.CurrentCulture); 
     else 
      return propertyValue; 
    } 

Приведенный выше код работает, но имеет недостаток: Код выше будет работать только если вы установите одно свойство для дубликата матча:

DuplicateValidationRule.Validate<IBankAccount>(newBankAccountEntry,new string[] {"AccountNumber"}); 

При добавлении еще одно свойство, чтобы проверить против, например:

DuplicateValidationRule.Validate<IBankAccount>(newBankAccountEntry,new string[] {"AccountNumber","Bank.Name"}); 

тогда код будет проверять второе свойство, на следующем появлении в списке. Он должен проверять все свойства в .Any для текущего сравниваемого объекта. Надеюсь, это заставляет, может быть, кто-то может дать мне несколько советов о том, как это исправить! Спасибо :)

ответ

1

Вот меня в предположении, что у вас есть BusinessObject сущность, и вы хотите, чтобы соответствовать ВСЕМ свойствам против другого в списке BusinessObjects:

public ValidationError Validate<T>(T entityProperty, string[] entityPropertyName) 
{     
    ICollection<T> businessObjectList = FetchObjectsByType<T>(); 
    Hashtable properties = EnumeratePropertyInfo<T>(entityProperty, entityPropertyName); 
    return businessObjectList.Any(obj => IsDuplicate<T>(obj, properties)) == true ? new ValidationError(_DuplicateMessage) : ValidationError.Empty; 
} 


private Hashtable EnumeratePropertyInfo<T>(T entityProperty, string[] entityPropertyName) 
{ 
    Hashtable properties = new Hashtable(); 
    for (int i = 0; i < entityPropertyName.Length; i++)   
    {    
     object value = getPropertyValue(entityProperty, entityPropertyName[i]); 
     properties.Add(entityPropertyName[i], value); 
    } 
    return properties; 
} 

// all properties must be matched for a duplicate to be found 
private bool IsDuplicate<T>(T entityProperty, Hashtable properties) 
{ 
    foreach(DictionaryEntry prop in properties) 
    { 
     var curValue = getPropertyValue(entityProperty, prop.Key.ToString()); 
     if (!prop.Value.Equals(curValue)) 
     { 
      return false; 
     } 
    } 
    return true; 
} 

Если вы, возможно, немного обеспокоенный использованием Hastable для сопоставлений свойств, тогда я бы посоветовал вам вместо этого создать свой собственный пользовательский тип.

Надеюсь, что это поможет.

+0

Похоже, ваш код может работать ... Это похоже на лучшее решение для того, которое я только что нашел. Позвольте мне опубликовать мое текущее решение, и, надеюсь, какой-то пользовательский ввод скажет мне, что лучше использовать. Большое спасибо!! – FaNIX

1

Если я не ошибаюсь прямо сейчас, вы проверяете уникальное существование каждого отдельного объекта, а не их комбинацию.

Вместо того, чтобы с помощью отражения вы не можете использовать метод Equals или интерфейс (например, IMyComparable.), Как это:

public interface IMyComparable<T> 
{ 
    bool MyComparableMethod(T account); 
} 

public interface IBankAccount : IMyBusinessObjectBase, IMyComparable<T> 
{ 
... 
    public bool MyComparableMethod(IBankAccount account) 
    { 
     return this.AccountNumber == account.AccountNumber && 
       this.Bank.Name == account.Bank.Name && 
       this.Id != account.Id; 
    } 
} 

public ValidationError Validate<T>(T entityProperty) where T : IMyComparable<T> 
{ 
... 
    if (!businessObjectList.Any(x => entityProperty.MyComparableMethod(x)) 
     return new ValidationError(_DuplicateMessage); 
... 

, чем в любой метод вы можете использовать метод MyComparableMethod, определенный в интерфейсе.

Надеется, что это помогает :)

+0

Я не уверен, что вы пытаетесь сделать. Вы правильно говорите, что на данный момент я проверяю уникальное существование каждого отдельного объекта, а не их комбинацию, что является моей проблемой. Пожалуйста, укажите полный пример того, что вы пытаетесь сказать? Помните, что seens принять любого типа бизнес-объекта, поэтому IMyComparable должен выглядеть примерно так: общедоступный интерфейс IMyComparable { BOOL MyComparableMethod (T объект); } – FaNIX

+0

Мой метод сравнения не идеален (например, не проверяет значение null), но я думаю, что теперь код выражает мою идею – marcob

0

Мое решение проблемы. Никаких изменений, внесенных в getPropertyValue. Пожалуйста, предоставьте свой ввод. Спасибо

public ValidationError Validate<T>(T entityProperty, string[] entityPropertyName) 
{ 
    ICollection<T> businessObjectList = 
     BusinessContextManagerService.Fetch<ICollection<T>>(Criteria.ActiveAndDormant); 

    bool res = true; 
    object entityPropertyValue = null; 

    // Only Checking one property 
    if (entityPropertyName.Length == 1) 
    { 
     entityPropertyValue = getPropertyValue(entityProperty, entityPropertyName[0]); 

     if (businessObjectList.Any(x => getPropertyValue(x, entityPropertyName[0]).Equals(entityPropertyValue) && 
            x.GetType().GetProperty("ID").GetValue(x, null).ToString() 
            != ((IBusinessObjectBase)entityProperty).ID.ToString())) 
      res &= true; 
     else 
      res &= false; 
    } 
    else 
    { 
     foreach (object obj in businessObjectList) 
     { 
      res = true; 
      int objID = (Int32)obj.GetType().GetProperty("ID").GetValue(obj, null); 

      for (int i = 0; i < entityPropertyName.Length; i++) 
      { 
       entityPropertyValue = getPropertyValue(entityProperty, entityPropertyName[i]); 
       object objValue = getPropertyValue(obj, entityPropertyName[i]); 

       if (objValue.Equals(entityPropertyValue) && objID != ((IBusinessObjectBase)entityProperty).ID) 
        res &= true; 
       else 
        res &= false; 

       if (res == false) 
        break; 
      } 

      if (res == true) 
       break; 
     } 
    } 

    if (res) 
     return new ValidationError(_DuplicateMessage); 
    else 
     return ValidationError.Empty; 
} 
+0

Ваше решение, несомненно, сделает трюк, однако для удобства чтения его немного загромождает. Также есть некоторый дублированный код. Вам следует попытаться немного реорганизовать его и делегировать его общим методам. Мое решение делает это красиво и снижает ваш метод Validate до 3 строк. Вы также можете улучшить метод дублирования, просто передав 2 набора свойств хэш-таблицы и сравнив их с помощью .Equals. Я обновлю его позже, чтобы показать вам. Однако, в конце концов, это ваше решение, что вы хотите сделать. – James

0

Я проверил ваш код с помощью Timespan и, похоже, занимает такое же количество времени, что и со мной. Ваш код выглядит намного приятнее, поэтому я пойду с вашим решением, большое спасибо за то, что нашли время, чтобы помочь мне.

PS: Мне нужно было изменить следующее, чтобы оно работало. Все юнит-тесты проходят сейчас :)

private bool IsDuplicate<T>(T entityProperty, Hashtable properties) 
    { 
     bool res = true; 

     foreach (DictionaryEntry prop in properties) 
     { 
      var curValue = getPropertyValue(entityProperty, prop.Key.ToString()); 
      if (prop.Value.Equals(curValue)) 
      { 
       res &= true; 
      } 
      else 
       res &= false; 
     } 
     return res; 
    } 
+0

Рад, что я мог помочь! Btw Я только что заметил, мой код действительно правильный для метода IsDuplicate, я просто забыл добавить! оператор должен быть «if (! prop.Value.Equals (curValue))». – James

+0

, имеющий флаг и постоянно устанавливающий его в true/false, довольно бессмысленен, поскольку как только он является ложным, вы знаете, что набор свойств не равен. Поэтому вы хотите выпрыгнуть из цикла как можно скорее. Я обновил мой IsDuplicateMethod – James

Смежные вопросы