我已经在这里花了数小时来寻找问题的答案,所以如果这是重复的查询,我们感到抱歉。如果是这样,请指出正确的方向。如果没有,请参见下文,我的任务如下:
创建一个可以动态检查数据库以查看某个对象是否存在值的函数。
[基本上,用户单击将项目移动到另一个舞台的按钮。下一阶段可能/可能不会在进入该阶段之前有要求。如果存在要求,则有两个数据点发送给我:
使用这两段数据,我需要检查数据库(最好通过DbSet,使用LINQ或Reflection。
ReflectionClass变量可以引用数据库中5个表之一。因此,从本质上讲,我需要一种表达方式:db.[DbSet].Any(w=>w.ID == PipelineID && w.[ReflectionProperty] != null)
或类似的内容...
我已经尝试过使用ExpressionTrees,但无法使Func<T,bool>
与Type
变量一起使用。请参阅下面的代码,这将起作用,但是我知道使用反射可以更有效地做到这一点,我只是不知道如何。
public async Task<Feedback> vStageReqFields(Guid NextStageID, Guid PipelineID)
{
Feedback f = new Feedback();
bool Valid = true;
string InvalidList = string.Empty;
List<Domain.Pipeline.Pipeline> pipelines = new List<Domain.Pipeline.Pipeline>();
List<Domain.Pipeline.Billing> billings = new List<Domain.Pipeline.Billing>();
try
{
//Get a list of Validations needed before advancing Stage...
var validations = db.PipelineStageRequiredFields.Any(a=>a.StageID == NextStageID) ? db.PipelineStageRequiredFields.Where(w=>w.StageID == NextStageID).ToList() : null;
//If Validations exist, start validatiing...
if(validations != null && validations.Any())
{
Type objectType = (from asm in AppDomain.CurrentDomain.GetAssemblies()
from type in asm.GetTypes()
where type.IsClass && type.FullName == "Domain.Pipeline.Pipeline" // static class to find Assembly info, all v.ReflectionClasses come from the same Assembly...
select type).SingleOrDefault();
foreach (var v in validations)
{
if(Utility.HasProperty(objectType, v.RefelectionProperty))//Check to see if ReflectionsClass has ReflectionProperty
{
//Switch Statement for Reflection Class to Check Property Value...
switch (v.RefelectionClass)
{
case "Domain.Pipeline.Pipeline":
pipelines = GetAllMembers(db, "Pipelines").OfType<Domain.Pipeline.Pipeline>().Where(w => w.ID == PipelineID).ToList(); //Get all Pipeline Objects...
if (pipelines.Any())
{
var model = pipelines.FirstOrDefault();
var value = model.GetType().GetProperty(v.RefelectionProperty).GetValue(model, null); //Check if Required ReflectionProperty has a value...
if (value == null)
{
Valid = false;
if (string.IsNullOrEmpty(InvalidList))
{
InvalidList = "The following fields are required: " + v.RefelectionProperty;
}
else
{
InvalidList = InvalidList + ", " + v.RefelectionProperty;
}
}
}
else
{
f.Success = false;
f.Type = FeedbackType.Error;
f.SuccessMsg = "Error: Could not find a Pipeline with this ID: '" + PipelineID.ToString() + "'";
}
break;
case "Domain.Pipeline.Billing":
billings = GetAllMembers(db, "Billings").OfType<Domain.Pipeline.Billing>().Where(w => w.PipelineID == PipelineID).OrderByDescending(o => o.EffectiveDate).ToList();
if (billings.Any())
{
var model = billings.FirstOrDefault();
var value = model.GetType().GetProperty(v.RefelectionProperty).GetValue(model, null);
if (value == null)
{
Valid = false;
if (string.IsNullOrEmpty(InvalidList))
{
InvalidList = "The following fields are required: " + v.RefelectionProperty;
}
else
{
InvalidList = InvalidList + ", " + v.RefelectionProperty;
}
}
}
else
{
f.Success = false;
f.Type = FeedbackType.Error;
f.SuccessMsg = "Error: Could not find a Pipeline with this ID: '" + PipelineID.ToString() + "'";
}
break;
default:
f.Success = false;
f.Type = FeedbackType.Error;
f.SuccessMsg = "Error: Could not find any Data in the " + v.RefelectionClass + " table for this Pipeline: '" + PipelineID.ToString() + "'";
break;
}
}
else
{
f.Success = false;
f.Type = FeedbackType.Error;
f.SuccessMsg = "The " + v.RefelectionClass + " does not have a Property of " + v.RefelectionProperty;
}
}
}
//No Validations Exist, User can proceed...
else
{
f.Success = true;
f.Type = FeedbackType.Success;
f.SuccessMsg = "Success! There are no required fields for the next stage.";
}
}
catch(Exception ex)
{
f.Success = false;
f.Type = FeedbackType.Error;
f.SuccessMsg = ITool.GetExceptionDetails(ex);
}
return f;
}
这里是另一个功能:
static IEnumerable GetAllMembers(DbContext DB, string dbSetName)
{
var model = DB.GetType().GetProperty(dbSetName);
return (IEnumerable)model.GetValue(DB);
}
考虑以下重构,以删除重复的代码并使它更干燥(不要重复自己)。
public Feedback vStageReqFields(Guid NextStageID, Guid PipelineID) {
Feedback feedback = new Feedback();
List<string> required = new List<string>();
List<string> errors = new List<string>();
StringBuilder msg = new StringBuilder();
try {
//Get a list of Validations needed before advancing Stage...
var validations = db.PipelineStageRequiredFields.Where(w => w.StageID == NextStageID);
//If Validations exist, start validatiing...
if (validations.Any()) {
foreach (var field in validations) {
var className = field.RefelectionClass;
object model = null;
//Switch Statement for Reflection Class to Check Property Value...
switch (className) {
case "Domain.Pipeline.Pipeline":
model = db.Pipelines.FirstOrDefault(p => p.ID == PipelineID);
break;
case "Domain.Pipeline.Billing":
model = db.Billings.Where(w => w.PipelineID == PipelineID).OrderByDescending(o => o.EffectiveDate).FirstOrDefault();
break;
default:
errors.Add("Could not find any Data in the " + className + " table for this Pipeline: '" + PipelineID.ToString() + "'");
continue;
}
validate(field, PipelineID, model, required, errors);
}
if (required.Any()) {
msg.Append("The following fields are required: ")
.AppendLine(string.Join(", ", required));
}
if (errors.Any()) {
msg.AppendLine(string.Join(Environment.NewLine, errors));
}
}
if (msg.Length > 0) {
feedback.Success = false;
feedback.Type = FeedbackType.Error;
feedback.SuccessMsg = msg.ToString();
} else {
feedback.Success = true;
feedback.Type = FeedbackType.Success;
feedback.SuccessMsg = "Success! There are no required fields for the next stage.";
}
} catch (Exception ex) {
feedback.Success = false;
feedback.Type = FeedbackType.Error;
feedback.SuccessMsg = ITool.GetExceptionDetails(ex);
}
return feedback;
}
使用强类型查找所需的对象模型。
支持的validate
方法如下所示>>
private void validate(PipelineStageRequiredField field, Guid PipelineID, object model, List<string> required, List<string> errors) { if (model != null) { var propertyName = field.RefelectionProperty; var objectType = model.GetType(); var propertyInfo = getProperty(objectType, propertyName); if (propertyInfo != null) { var isValidModel = buildRequiredFieldCheckDelegate(objectType, propertyInfo); if (!(bool)isValidModel.DynamicInvoke(model)) { required.Add(propertyInfo.Name); } } else { errors.Add("The " + field.RefelectionClass + " does not have a Property of " + propertyName); } } else { errors.Add("Error: Could not find a " + field.RefelectionClass + " with this Pipeline: '" + PipelineID.ToString() + "'"); } } private static PropertyInfo getProperty(Type type, string propertyName) { return type.GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase); }
可以在其中构建表达式以检查必填字段是否具有值的地方
private Delegate buildRequiredFieldCheckDelegate(Type type, PropertyInfo propertyInfo) {
//Func<T, bool>
var delegateType = typeof(Func<,>).MakeGenericType(type, typeof(bool));
var prpertyDefaultValue = getDefaultValue(propertyInfo.PropertyType);
// p => p.Property != default(typeof(TProperty))
// p =>
var parameter = Expression.Parameter(type, "p");
// p => p.Property
var property = Expression.Property(parameter, propertyInfo);
// default(TProperty);
var defaultValue = Expression.Constant(prpertyDefaultValue);
// p => p.Property != default(TProperty)
var body = Expression.NotEqual(property, defaultValue);
// Func<T, bool> = T p => p.Property != default(TProperty)
var lambda = Expression.Lambda(delegateType, body, parameter);
return lambda.Compile();
}
private static object getDefaultValue(Type type) {
return type.IsValueType ? Activator.CreateInstance(type) : null;
}