我有一个固定长度的数据文件需要持久化到数据库中。我使用XML文件来定义字段的长度,并使用FieldItem类列表来存储数据。
class FieldItem
{
public string ObjectName {get; set;}
public string ObjectProperty {get; set;}
public string ObjectValue {get; set;}
public FieldItem()
{
}
}
所以FieldItem看起来像
var fieldItem = new FieldItem
{
ObjectName = "Company",
ObjectProperty = "Name",
ObjectValue = "ABC Corp."
}
获取FieldItem列表后,我将进行反思以创建Company和其他域对象以将它们保存到数据库中。
但在将它们保存到数据库之前,我需要应用一些业务规则来验证数据行。我的数据行看起来像:
var fieldItemList = new List<FieldItem>(){
new FieldItem {
ObjectName="Company",
ObjectProperty = "Name",
ObjectValue = "ABC"
}
new FieldItem{
ObjectName = "Product",
ObjectProperty = "ProductCode",
ObjectValue ="XYZ0123"
new FieldItem{
ObjectName = "Product",
ObjectProperty = "ProductName",
ObjectValue ="Christmas Tree"
}
// other FieldItem objects...
}
例如,我的规则是检查公司是否==“ABC”和ProductCode ==“XYZ0123”。这些规则由用户创建并作为字符串存储在数据库中。我现在正在做的是使用Microsoft的System.Linq.Dynamic来评估规则,例如
string validationRule = " (ObjectName == \"Company\" And ObjectProperty=\"CompanyName\" And ObjectValue = \"ABC Corp.\") And (ObjectName == \"Product\" And ObjectProperty=\"ProductCode\" And ObjectValue = \"XYZ0123\") ";
var query = fieldItemList.AsQuerable().Where(validationRule);
然后检查它是否有一行返回以告知该数据行是否已通过该规则。 显然,它太冗长了。你有更好的建议吗?如果我只喜欢我的规则表达式,那该怎么办?“Company.CompanyName ='ABC Corp.'和Product.ProductCode ='XYZ001'“?
答案 0 :(得分:1)
考虑使用FileHelpers库将文件直接解析为常规.NET域对象。我相信这一点,结合您的Dynamic Linq方法,将为您提供您正在寻找的语法。
答案 1 :(得分:1)
RE:“如果我只喜欢我的规则表达式,我应该怎么做:”Company.CompanyName ='ABC Corp'和Product.ProductCode ='XYZ001'“?
将此用户友好的查询:“Company.CompanyName ='ABC Corp' AND Product.ProductCode ='XYZ001'”映射到对您的数据结构友好的内容(FieldItem):
“ObjectName ='Company'AND ObjectProperty ='CompanyName'ANDVarValue ='ABC Corp' OR ObjectName ='Product'AND ObjectProperty ='ProductCode'AND ObjectValue ='XYZ001'”
如何知道用户的规则是否通过规则?计算条件数,如果它匹配fieldItemList.AsQueryable()的结果计数。其中(itemFieldFriendlyQuery),则数据行根据用户的规则有效。
一些基本映射器(使用正则表达式或滚动自己的解析器以使以下代码真正有效):
public Form3()
{
InitializeComponent();
string userFriendlyQuery = "Company.CompanyName = 'ABC Corp' AND Product.ProductCode = 'XYZ001'";
string[] queryConditions = userFriendlyQuery.Split(new string[]{" AND "},StringSplitOptions.None);
int conditionsCount = queryConditions.Length;
string itemFieldFriendlyQuery = string.Join(" OR ",
queryConditions.Select(condition =>
{
var conditionA = condition.Split(new string[] { " = " }, StringSplitOptions.None);
var left = conditionA[0];
var leftA = left.Split('.');
string objectName = leftA[0];
string objectProperty = leftA[1];
var right = conditionA[1];
return string.Format("ObjectName = '{0}' AND ObjectProperty = '{1}' AND ObjectValue = {2}",
objectName, objectProperty, right);
}
).ToArray());
MessageBox.Show(itemFieldFriendlyQuery);
// outputs: "ObjectName = 'Company' AND ObjectProperty = 'CompanyName' AND ObjectValue = 'ABC Corp' OR ObjectName = 'Product' AND ObjectProperty = 'ProductCode' AND ObjectValue = 'XYZ001'"
bool isValid = fieldItemList.AsQueryable().Where(itemFieldFriendlyQuery).Count() == conditionsCount;
MessageBox.Show(isValid.ToString());
}
答案 2 :(得分:0)
您可以将它们作为C#代码表达式存储在数据库中,然后使用CodeDom类将其解析并编译为一个类型,该类型公开将运行比较的方法。
这将创建许多临时程序集,这将是一个要管理的PITA,IMO。
相反,我仍然使用C#表示法来表达语法,但不是将其编译成代码,而是动态创建一个lambda表达式(通过Expression类),然后编译成一个获取所有参数的委托(你将这里需要一个映射机制,然后使用你创建的类型调用它。
答案 3 :(得分:0)
对于你的FieldItem
类,你不能创建一个可以注入Predicate委托方法的属性,这样:
class FieldItem
{
public string ObjectName {get; set;}
public string ObjectProperty {get; set;}
public string ObjectValue {get; set;}
public Predicate<FieldItem> EvalMethod { private get; set; }
public FieldItem()
{
}
public bool Evaluate()
{
return EvalMethod(this);
}
}
然后,您可以使用以下内容构建FieldItem
对象:
new FieldItem { ObjectName = "SomeObject",
ObjectProperty = "SomeProperty",
ObjectValue = "SomeValue",
EvalMethod = GetEvalMethodFor("SomeObject")
}
当然,您必须拥有某种解析器(上面的GetEvalMethodFor
方法)才能将validationRule字符串转换为布尔评估方法。
在您的收藏中,您可以在Evaluate()
圈内拨打foreach
。
<强>更新强>
如果您需要评估列表中的每个对象,可以执行以下操作:
bool areAllItemsValid = true;
foreach (var f in fieldItemList)
{
areAllItemsValid = areAllItemsValid && f.Evaluate();
if (areAllItemsValid)
{
continue;
}
else
{
return false;
}
}
return true;
您可以选择继承List<FieldItem>
并使EvaluateAll()
方法包含上述内容,或者将其声明为单独对象中的方法。
答案 4 :(得分:0)
顺便说一下:为什么要用class而不是struct?
数据的值类型,行为的引用类型。