-
-
Save SeanKilleen/1fa043025fed436eecc3 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// An example of one specific filter | |
[FilterName("IsMDL")] // this attribute is used to find the | |
public class ClaimsReportIsMDLFilter : NullableBoolFilter, ISearchFilter<vSEARCH_ClaimsReport> | |
{ | |
public Expression<Func<vSEARCH_ClaimsReport, bool>> GetExpression(string valuesToProcess) | |
{ | |
Expression<Func<vSEARCH_ClaimsReport, bool?>> selector = item => item.IsMDL; // this sets the field | |
// this uses the expression extensions to get the standard expression and then apply it to IsMDL | |
var composed = selector.Compose(base.GetFilterFunc(valuesToProcess)); | |
var predicate = PredicateBuilder.False<vSEARCH_ClaimsReport>(); | |
predicate = predicate.Or(composed); | |
return predicate; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This test passes. | |
public class ClaimsReportIsMDLFilterTests | |
{ | |
// ReSharper disable InconsistentNaming | |
private readonly vSEARCH_ClaimsReport ItemWithMDL = new vSEARCH_ClaimsReport { IsMDL = true }; | |
private readonly vSEARCH_ClaimsReport ItemWithoutMDL = new vSEARCH_ClaimsReport { IsMDL = false }; | |
private readonly vSEARCH_ClaimsReport ItemWithNullMDL = new vSEARCH_ClaimsReport { IsMDL = null }; | |
// ReSharper restore InconsistentNaming | |
[Fact] | |
public void WithSearchValueOf1_HidesNonMDLAndNull() | |
{ | |
var sut = this.GetCompiledExpressionForValues("1"); | |
sut.Invoke(ItemWithMDL).Should().BeTrue(); | |
sut.Invoke(ItemWithoutMDL).Should().BeFalse(); | |
sut.Invoke(ItemWithNullMDL).Should().BeFalse(); | |
} | |
private Func<vSEARCH_ClaimsReport, bool> GetCompiledExpressionForValues(string searchValue) | |
{ | |
return new ClaimsReportIsMDLFilter().GetExpression(searchValue).Compile(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This code happens in a method called "ClaimsReport" which takes in a NameValueCollection. | |
// ... | |
var filter = PredicateBuilder.True<vSEARCH_ClaimsReport>(); // predicate that evaluates to true. | |
var extractor = new SearchGridAttributeExtractor(nvc); // extracts items from the NameValueCollection | |
// a dictionary of attribute names and their respective search strings | |
var filterColumnsAndValues = extractor.AllPopulatedNonStandardAttributeNamesAndTheirSearchValues(); | |
//Gets all of the associated search classes, loops through them to get their expressions based on the | |
//search values. | |
var filters = new SearchFilterLocator<vSEARCH_ClaimsReport>().GetPredicateExpressionsFromListOfFilters(filterColumnsAndValues); | |
// Adds each inner filter as an "And" to the PredicateBuilder, so it becomes an "And" join | |
// of several potential inner "or" joins. | |
foreach (var filterItem in filters) | |
{ | |
filter = filter.And(filterItem); | |
} | |
//if we were to do the following instead, it would work | |
filter = filter.And(x=> x.IsMDL == true); | |
// ... | |
// Then, the code calls into a method which uses a SqlExpressionVisitor and passes this list of expressions into | |
// a where clause, where it bombs. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// these are 100% thanks to Servy on StackOverflow. See http://stackoverflow.com/a/23499052/316847 for more. | |
//According to servy: | |
// What this is doing is replacing all instances of the second expression's parameter with the body of the | |
// first expression, effectively inlining that expression into the second. The rest is simply replacing all of | |
// the parameters with a new single parameter and wrapping it back up into a lambda. | |
public static class ExpressionExtensions | |
{ | |
public static Expression<Func<TFirstParam, TResult>> Compose<TFirstParam, TIntermediate, TResult> | |
(this Expression<Func<TFirstParam, TIntermediate>> first, | |
Expression<Func<TIntermediate, TResult>> second) | |
{ | |
var param = Expression.Parameter(typeof(TFirstParam), "param"); | |
var newFirst = first.Body.Replace(first.Parameters[0], param); | |
var newSecond = second.Body.Replace(second.Parameters[0], newFirst); | |
return Expression.Lambda<Func<TFirstParam, TResult>>(newSecond, param); | |
} | |
public static Expression Replace(this Expression expression, | |
Expression searchEx, Expression replaceEx) | |
{ | |
return new ReplaceVisitor(searchEx, replaceEx).Visit(expression); | |
} | |
internal class ReplaceVisitor : ExpressionVisitor | |
{ | |
private readonly Expression from, to; | |
public ReplaceVisitor(Expression from, Expression to) | |
{ | |
this.from = from; | |
this.to = to; | |
} | |
public override Expression Visit(Expression node) | |
{ | |
return node == from ? to : base.Visit(node); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This is where we have to get the data. | |
//... | |
columns = columns.Where(x => !string.IsNullOrEmpty(x)).ToArray(); | |
//Column Count | |
int columnCount = columns.Count(); | |
string countSql = String.Format("SELECT DISTINCT {0} FROM {1}", string.Join(", ", columns), | |
typeof(DALType).GetTableName()); | |
SqlExpressionVisitor<DALType> evCount = OrmLiteConfig.DialectProvider.ExpressionVisitor<DALType>(); | |
evCount.Select(countSql); | |
if (filter != null) | |
{ | |
// this is the code that throws the error. | |
evCount.Where(filter); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// The generic filter that we pull from | |
public class NullableBoolFilter : IGenericSearchFilter<bool?> | |
{ | |
public Expression<Func<bool?, bool>> GetFilterFunc(string valuesToProcess) | |
{ | |
var acceptableValues = new List<bool?>(); | |
if (string.IsNullOrWhiteSpace(valuesToProcess)) | |
{ | |
// all values acceptable | |
acceptableValues = new List<bool?>{true, false, null}; | |
} | |
else | |
{ | |
if (!valuesToProcess.Contains("0") && !valuesToProcess.Contains("1")) | |
{ | |
throw new ArgumentException("Invalid Nullable boolean filter attribute specified"); | |
} | |
if (valuesToProcess.Contains("0")) | |
{ | |
acceptableValues.Add(false); | |
} | |
if (valuesToProcess.Contains("1")) | |
{ | |
acceptableValues.Add(true); | |
} | |
} | |
// returns the expression based on whatever the item is contained in the acceptable values | |
return item => acceptableValues.Any(x=> x == item); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment