我正在尝试使这个Generic DuplicateValidationRule工作,它基本上检查Collection是否有重复项(基于传入的通用业务对象类型)。让我们以IBankAccount业务对象为例:
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,Address,BankAccount,Bank,BankBranch等)string [] entityPropertyName =检查重复项时要包含的属性数组。
现在让我们使用以下参数:假设我想检查重复的BankAccounts,检查帐号和银行。帐号在银行中是唯一的,但可以存在于另一家银行。因此,如果您查看上面的列表,Acc1,Acc2和Acc3是有效的。 Acc4无效,因为该银行的帐号已存在。
因此,对validate的调用看起来像这样。
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中所有被比较的对象的属性。希望这有用,也许有人可以就如何解决这个问题给我一些建议!谢谢:))
答案 0 :(得分: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方法。
希望这会有所帮助:)
答案 1 :(得分: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进行属性映射,那么我建议您为此创建自己的自定义类型。
希望有所帮助。
答案 2 :(得分: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;
}
答案 3 :(得分: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;
}