I'm trying to write following LINQ query using ServiceStack Ormlite.
dbConn.Select<Product>(p => p.IsActive.HasValue && p.IsActive.Value)
Here, Product is my item class and "IsActive" is Nullable Bool property in that class. When this line executes it always throws "InvalidOperationException" with the message
variable 'p' of type '' referenced from scope '', but it is not defined
I tried different variants as following but still same exception result
dbConn.Select<Product>(p => p.IsActive.HasValue == true && p.IsActive.Value == true)
dbConn.Select<Product>(p => p.IsActive != null && p.IsActive.Value == true)
But if I just write
dbConn.Select<Product>(p => p.IsActive.HasValue)
then it works.
I'm puzzled what is the problem? Is this servicestack ormlite issue?
My answer can handle Nullable value like "value" and "HasValue" with servicestack ormlite. And But also with datetime nullable ,like 'createdate.value.Year'.
you must change two place.
modify VisitMemberAccess method:
protected virtual object VisitMemberAccess(MemberExpression m)
{
if (m.Expression != null)
{
if (m.Member.DeclaringType.IsNullableType())
{
if (m.Member.Name == nameof(Nullable<bool>.Value))
return Visit(m.Expression);
if (m.Member.Name == nameof(Nullable<bool>.HasValue))
{
var doesNotEqualNull = Expression.NotEqual(m.Expression, Expression.Constant(null));
return Visit(doesNotEqualNull); // Nullable<T>.HasValue is equivalent to "!= null"
}
throw new ArgumentException(string.Format("Expression '{0}' accesses unsupported property '{1}' of Nullable<T>", m, m.Member));
}
if (m.Member.DeclaringType == typeof(DateTime))
{
var ExpressionInfo = m.Expression as MemberExpression;
if (ExpressionInfo.Member.DeclaringType.IsNullableType())
{
if (ExpressionInfo.Member.Name == nameof(Nullable<bool>.Value))
{
var modelType = (ExpressionInfo.Expression as MemberExpression).Expression.Type;
var tableDef = modelType.GetModelDefinition();
var columnName = (ExpressionInfo.Expression as MemberExpression).Member.Name;
var QuotedColumnName = GetQuotedColumnName(tableDef, columnName);
if (m.Member.Name == "Year")
{
return new PartialSqlString(string.Format("DATEPART(yyyy,{0})", QuotedColumnName));
}
if (m.Member.Name == "Month")
return new PartialSqlString(string.Format("DATEPART(mm,{0})", QuotedColumnName));
}
if (ExpressionInfo.Member.Name == nameof(Nullable<bool>.HasValue))
{
var doesNotEqualNull = Expression.NotEqual(ExpressionInfo.Expression, Expression.Constant(null));
return Visit(doesNotEqualNull); // Nullable<T>.HasValue is equivalent to "!= null"
}
}
else
{
var modelType = ExpressionInfo.Expression.Type;
var tableDef = modelType.GetModelDefinition();
var columnName = ExpressionInfo.Member.Name;
var QuotedColumnName = GetQuotedColumnName(tableDef, columnName);
if (m.Member.Name == "Year")
return new PartialSqlString(string.Format("DATEPART(yyyy,{0})", QuotedColumnName));
if (m.Member.Name == "Month")
return new PartialSqlString(string.Format("DATEPART(mm,{0})", QuotedColumnName));
}
}
if (m.Expression.NodeType == ExpressionType.Parameter || m.Expression.NodeType == ExpressionType.Convert)
{
var propertyInfo = (PropertyInfo)m.Member;
var modelType = m.Expression.Type;
if (m.Expression.NodeType == ExpressionType.Convert)
{
var unaryExpr = m.Expression as UnaryExpression;
if (unaryExpr != null)
{
modelType = unaryExpr.Operand.Type;
}
}
var tableDef = modelType.GetModelDefinition();
if (propertyInfo.PropertyType.IsEnum)
return new EnumMemberAccess(
GetQuotedColumnName(tableDef, m.Member.Name), propertyInfo.PropertyType);
return new PartialSqlString(GetQuotedColumnName(tableDef, m.Member.Name));
}
}
var member = Expression.Convert(m, typeof(object));
var lambda = Expression.Lambda<Func<object>>(member);
var getter = lambda.Compile();
return getter();
}
modify VisitLambda method :
protected virtual object VisitLambda(LambdaExpression lambda)
{
if (lambda.Body.NodeType == ExpressionType.MemberAccess && sep == " ")
{
MemberExpression m = lambda.Body as MemberExpression;
if (m.Expression != null)
{
string r = VisitMemberAccess(m).ToString();
if (m.Member.DeclaringType.IsNullableType())
return r;
return string.Format("{0}={1}", r, GetQuotedTrueValue());
}
}
return Visit(lambda.Body);
}
This is nature of the Linq. In order to achieve what you need, you will need to use two where closes:
dbConn.Where<Product>(p => p.IsActive.HasValue).Where(p=>p.Value==true);
Related
I am trying to test my ViewComponent with XUnit.
When I debug through the component and set a break point right before it returns the Component View, the model is set.
Here is the simple model I am returning.
public class IntDashMakeRecAssgnmntsPoRespMngrVM
{
public IEnumerable<Audit> Audits { get; set; }
}
And I am trying to assert the Audits.Count() is greater than 0.
Here is my View Component:
public class IntDashMakeRecAssgnmntsPoRespMngrViewComponent : ViewComponent
{
private IAuditRepository _auditRepo;
private IExternalRepository _externalRepo;
public IntDashMakeRecAssgnmntsPoRespMngrViewComponent(IAuditRepository auditRepo,
IExternalRepository externalRepo)
{
_auditRepo = auditRepo;
_externalRepo = externalRepo;
}
public IViewComponentResult Invoke()
{
ClaimsPrincipal user = HttpContext.Request.HttpContext.User;
short staffId = short.Parse(user.Claims.Single(c => c.Type == "StaffId").Value);
// Get all Internal Audits that are not closed and not completed
var audits = _auditRepo.Audits
.Include(a => a.Findings).ThenInclude(f => f.Recommendations).ThenInclude(r => r.Assignments)
.Where(a => a.StatusID != 3 && a.StatusID != 11);
var external = _externalRepo.ExternalRecords;
audits = audits.Where(a => !external.Any(e => e.AuditID == a.AuditID));
if (User.IsInRole("PAG_SPEC") && !User.IsInRole("PAG_ADMIN_INT"))
{
audits = audits.Where(a =>
a.Assignments.Any(assn => assn.AssignmentAuditId == a.AuditID
&& assn.AssignmentRoleId == 2 && assn.AssignmentStaffId == staffId));
}
// Where audit has a recommendation without an assigned PO Authorizer
// OR without an assigned Responsible Manager (Rec Level).
List<Audit> auditsToAssign = new List<Audit>();
foreach (Audit audit in audits)
{
foreach (Finding finding in audit.Findings)
{
foreach (Recommendation rec in finding.Recommendations)
{
if (!rec.Assignments.Any(asgn => asgn.AssignmentRoleId == 15)
|| !rec.Assignments.Any(asgn => asgn.AssignmentRoleId == 26)
)
{
auditsToAssign.Add(rec.Finding.Audit);
break;
}
}
}
}
IntDashMakeRecAssgnmntsPoRespMngrVM intDashMakeRecAssgnmntsPoRespMngrVM =
new IntDashMakeRecAssgnmntsPoRespMngrVM
{
Audits = auditsToAssign
};
return View("/Views/InternalAudit/Components/Dashboard/IntDashMakeRecAssgnmntsPoRespMngr/Default.cshtml", intDashMakeRecAssgnmntsPoRespMngrVM);
}
}
When I get to this line in debugging and break to inspect, I have 1 Audit which I want:
return View("/Views/InternalAudit/Components/Dashboard/IntDashMakeRecAssgnmntsPoRespMngr/Default.cshtml", intDashMakeRecAssgnmntsPoRespMngrVM);
Now here is my Unit Test:
[Fact]
public void ReturnsAudit_1Finding_1Rec_1Asgn_PONeeded_RespMnrAssigned()
{
// Arrange
var audits = new Audit[]
{
new Audit { AuditID = 1 }
};
var findings = new Finding[]
{
new Finding{ Audit = audits[0], FindingId = 1 } // 1 Finding
};
var recommendations = new List<Recommendation>()
{
new Recommendation // 1 Rec
{
Finding = findings[0],
Assignments = new List<Assignment>()
{
// PO Authorizor
new Assignment { AssignmentRoleId = 15 }
// No Responsible Manager
}
}
};
audits[0].Findings = findings;
findings[0].Recommendations = recommendations;
Mock<IAuditRepository> mockAuditRepo = new Mock<IAuditRepository>();
mockAuditRepo.Setup(m => m.Audits).Returns(audits.AsQueryable());
Mock<IExternalRepository> mockExternalRepo = new Mock<IExternalRepository>();
mockExternalRepo.Setup(m => m.ExternalRecords).Returns(
new External[0].AsQueryable()
);
// Act
var component = new IntDashMakeRecAssgnmntsPoRespMngrViewComponent(
mockAuditRepo.Object, mockExternalRepo.Object);
component.ViewComponentContext = new ViewComponentContext();
component.ViewComponentContext.ViewContext.HttpContext = TestContext;
var result =
component.Invoke() as IntDashMakeRecAssgnmntsPoRespMngrVM;
int auditCount = (result).Audits.Count();
// Assert
Assert.Equal(1, auditCount);
}
Why is result null on this line?
var result =
component.Invoke() as IntDashMakeRecAssgnmntsPoRespMngrVM;
I also tried this first and it is still null:
ViewComponentResult result =
component.Invoke() as ViewComponentResult;
int auditCount =
((IntDashMakeRecAssgnmntsPoRespMngrVM)result.Model).Audits.Count();
I figured it out.
I wasn't casting the result to the right type.
I had this:
ViewComponentResult result =
component.Invoke() as ViewComponentResult;
int auditCount =
((IntDashMakeRecAssgnmntsPoRespMngrVM)result.Model).Audits.Count();
It should be this:
var result =
component.Invoke() as ViewViewComponentResult;
int auditCount =
((IntDashMakeRecAssgnmntsPoRespMngrVM)result.ViewData.Model).Audits.Count();
ViewViewComponentResult instead of ViewComponentResult.
I have a repository with this method
public virtual IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> filter = null, Func<IQueryable<TEntity>,
IOrderedQueryable<TEntity>> orderBy = null, string includeProperties = "");
I have a method that is using it as such to get a user to work on
var user = this.applicationUserRepository.Get(x => x.EmailAddress == userName).FirstOrDefault();
It then calls the same method with a different expression further in the method as follows to check the user working on the first user
var changingUser = this.applicationUserRepository.Get(x => x.Id == changingUserId).FirstOrDefault();
I am trying to mock the repository with two setups to call it twice in the same test.
string emailAddress = "myaddresss#test.com";
int changingUserId = 5;
var targetUsers = new List<ApplicationUser>
{
new ApplicationUser { Id = 1, Password = "Testing123", EmailAddress = emailAddress }
};
// Setup the user that will be modified to be found
var mockApplicationUserRepository = new Mock<IRepository<ApplicationUser>>();
mockApplicationUserRepository
.Setup(aur => aur.Get(x => x.EmailAddress == userName, null, string.Empty))
.Returns(targetUsers.AsEnumerable());
// Set up to query the changing user to not be found
mockApplicationUserRepository
.Setup(aur2 => aur2.Get(x => x.Id == changingUserId, null, string.Empty))
.Returns(new List<ApplicationUser>().AsEnumerable()); // Empty list
Even though the second call will never be hit, for this test, I want to learn how to set this up.
When I run the test the first call
var user = this.applicationUserRepository.Get(x => x.EmailAddress == userName).FirstOrDefault();
I get null
If I change the mock to have
It.IsAny<Expression<Func<ApplicationUser, bool>>>()
I get the expected user back.
I can not figure out how I will set the two calls up so it will know which expression to use. Any help will be appreciated.
The problem is that Moq does not compare the expressions you use (only reference equality).
Using this little helper class:
public static class LambdaCompare
{
public static bool Eq<TSource, TValue>(
Expression<Func<TSource, TValue>> x,
Expression<Func<TSource, TValue>> y)
{
return ExpressionsEqual(x, y, null, null);
}
public static Expression<Func<Expression<Func<TSource, TValue>>, bool>> Eq<TSource, TValue>(Expression<Func<TSource, TValue>> y)
{
return x => ExpressionsEqual(x, y, null, null);
}
private static bool ExpressionsEqual(Expression x, Expression y, LambdaExpression rootX, LambdaExpression rootY)
{
if (ReferenceEquals(x, y)) return true;
if (x == null || y == null) return false;
var valueX = TryCalculateConstant(x);
var valueY = TryCalculateConstant(y);
if (valueX.IsDefined && valueY.IsDefined)
return ValuesEqual(valueX.Value, valueY.Value);
if (x.NodeType != y.NodeType
|| x.Type != y.Type) return false;
if (x is LambdaExpression)
{
var lx = (LambdaExpression) x;
var ly = (LambdaExpression) y;
var paramsX = lx.Parameters;
var paramsY = ly.Parameters;
return CollectionsEqual(paramsX, paramsY, lx, ly) && ExpressionsEqual(lx.Body, ly.Body, lx, ly);
}
if (x is MemberExpression)
{
var mex = (MemberExpression) x;
var mey = (MemberExpression) y;
return Equals(mex.Member, mey.Member) && ExpressionsEqual(mex.Expression, mey.Expression, rootX, rootY);
}
if (x is BinaryExpression)
{
var bx = (BinaryExpression) x;
var by = (BinaryExpression) y;
return bx.Method == #by.Method && ExpressionsEqual(bx.Left, #by.Left, rootX, rootY) &&
ExpressionsEqual(bx.Right, #by.Right, rootX, rootY);
}
if (x is ParameterExpression)
{
var px = (ParameterExpression) x;
var py = (ParameterExpression) y;
return rootX.Parameters.IndexOf(px) == rootY.Parameters.IndexOf(py);
}
if (x is MethodCallExpression)
{
var cx = (MethodCallExpression)x;
var cy = (MethodCallExpression)y;
return cx.Method == cy.Method
&& ExpressionsEqual(cx.Object, cy.Object, rootX, rootY)
&& CollectionsEqual(cx.Arguments, cy.Arguments, rootX, rootY);
}
throw new NotImplementedException(x.ToString());
}
private static bool ValuesEqual(object x, object y)
{
if (ReferenceEquals(x, y))
return true;
if (x is ICollection && y is ICollection)
return CollectionsEqual((ICollection) x, (ICollection) y);
return Equals(x, y);
}
private static ConstantValue TryCalculateConstant(Expression e)
{
if (e is ConstantExpression)
return new ConstantValue(true, ((ConstantExpression) e).Value);
if (e is MemberExpression)
{
var me = (MemberExpression) e;
var parentValue = TryCalculateConstant(me.Expression);
if (parentValue.IsDefined)
{
var result =
me.Member is FieldInfo
? ((FieldInfo) me.Member).GetValue(parentValue.Value)
: ((PropertyInfo) me.Member).GetValue(parentValue.Value);
return new ConstantValue(true, result);
}
}
if (e is NewArrayExpression)
{
var ae = ((NewArrayExpression) e);
var result = ae.Expressions.Select(TryCalculateConstant);
if (result.All(i => i.IsDefined))
return new ConstantValue(true, result.Select(i => i.Value).ToArray());
}
return default(ConstantValue);
}
private static bool CollectionsEqual(IEnumerable<Expression> x, IEnumerable<Expression> y, LambdaExpression rootX, LambdaExpression rootY)
{
return x.Count() == y.Count()
&& x.Select((e, i) => new {Expr = e, Index = i})
.Join(y.Select((e, i) => new { Expr = e, Index = i }),
o => o.Index, o => o.Index, (xe, ye) => new { X = xe.Expr, Y = ye.Expr })
.All(o => ExpressionsEqual(o.X, o.Y, rootX, rootY));
}
private static bool CollectionsEqual(ICollection x, ICollection y)
{
return x.Count == y.Count
&& x.Cast<object>().Select((e, i) => new { Expr = e, Index = i })
.Join(y.Cast<object>().Select((e, i) => new { Expr = e, Index = i }),
o => o.Index, o => o.Index, (xe, ye) => new { X = xe.Expr, Y = ye.Expr })
.All(o => Equals(o.X, o.Y));
}
private struct ConstantValue
{
public ConstantValue(bool isDefined, object value) : this()
{
IsDefined = isDefined;
Value = value;
}
public bool IsDefined { get; private set; }
public object Value { get; private set; }
}
}
you can setup your mock like this:
Expression<Func<ApplicationUser, bool>> expr = x => x.EmailAddress == emailAddress;
var mockApplicationUserRepository = new Mock<IRepository<ApplicationUser>>();
mockApplicationUserRepository
.Setup(aur => aur.Get(It.Is<Expression<Func<ApplicationUser, bool>>>(x => LambdaCompare.Eq(x, expr)), null, string.Empty))
.Returns(targetUsers.AsEnumerable());
Just adding a comment to this old answer (though quite useful code)
This version of LambdaCompare class is missing a case to compare an UnaryExpression, something which is included in the code in the original post.
Use that code instead of this (I learnt the hard way...)
// update information from this reponse to database
public bool UpdatePassengerInformation(GetResponse response)
{
try
{
using (MyEntities context = new MyEntities())
{
var masterID = (from Id in context.BookMaster where Id.BookingId == response.BookingId select Id.MasterId).First();
if (masterID != null)
{
for (int i = 0; i < response.Book.Length; i++)
{
var passenger_info = from passenger in context.BookPassenger
where passenger.BookID == masterID &&
assenger.FirstName == response.Book[i].FirstName && passenger.LastName == response.Book[i].LastName select passenger;
// in below loop i got exception "The LINQ expression node type 'ArrayIndex' is not supported in LINQ to Entities."
foreach (BookPassenger book_passenger in passenger_info)
{
book_passenger.TicketId = response.Book[i].TicketId;
book_passenger.TicketNumber = response.Book[i].TicketNumber;
}
}
context.SaveChanges();
}
}
return true;
}
catch (Exception ex)
{
throw ex;
}
}
So don't use it in query, just assign a new variable and use this one.
for (int i = 0; i < response.Book.Length; i++)
{
var responseBook = response.Book[i];
var passenger_info = from passenger in context.BookPassenger
where passenger.BookID == masterID &&
assenger.FirstName == responseBook.FirstName && passenger.LastName == responseBook.LastName select passenger;
foreach (BookPassenger book_passenger in passenger_info)
{
book_passenger.TicketId = responseBook.TicketId;
book_passenger.TicketNumber = responseBook.TicketNumber;
}
}
I have an application where all queries are created dynamically based on a simple data message received by a WCF service. A data message is, put simply, a collection of columnname/column value pairs, with the addition of an operator, e.g. Equals, Less Than, etc.
Simple Data Message of ColumnName-Value-Operator
Name, Joe, Equals
Age, 35, Less Than
Occupation, Geek, Equals
Rate, 1000, Greater Than
etc...
I have been somewhat successfully using dynamic binary expressions based on the contents of the datamessage.
BinaryExpression expression = null;
ParameterExpression parameter = Expression.Parameter(typeof(MessageType), "p");
foreach (row in DataMessage)
{
BinaryExpression exp = DataLib.MakeQueryFilter(typeof(MessageType),
row.ColumnName,row.ColumnValue,column.DataOperator.ToString(), parameter);
expression = expression == null ? exp : Expression.AndAlso(expression, exp);
results = DataContext.MessageType.Where(Expression.Lambda<Func<Media, bool>>(expression, parameter));
}
public static BinaryExpression MakeQueryFilter(Type type, string propertyName, object value, string dataoperator, ParameterExpression parameter)
{
//var type = oType.GetType();
object queryvalue = null;
var property = type.GetProperty(propertyName);
Type propertyType = property.PropertyType;
if ((propertyType.IsGenericType) && (propertyType.GetGenericTypeDefinition() == typeof(Nullable)))
propertyType = propertyType.GetGenericArguments()[0];
// convert the value appropriately
if (propertyType == typeof(System.Int32))
queryvalue = Convert.ToInt32(value);
if (property.PropertyType == typeof(DateTime))
queryvalue = Convert.ToDateTime(value);
if (property.PropertyType == typeof(Double))
queryvalue = Convert.ToDouble(value);
if (property.PropertyType == typeof(String))
queryvalue = Convert.ToString(value);
if (property.PropertyType == typeof(Guid))
queryvalue = new Guid(value.ToString());
var propertyAccess = Expression.MakeMemberAccess(parameter, property);
var constantValue = Expression.Constant(queryvalue);
Type[] types = new Type[2];
types.SetValue(typeof(Expression), 0);
types.SetValue(typeof(Expression), 1);
var methodInfo = typeof(Expression).GetMethod(dataoperator, types);
var equality2 = (BinaryExpression)methodInfo.Invoke(null, new object[] { propertyAccess, constantValue });
return equality2;
}
The problem I am encountering is when I want to query through a relationship to a value in another table, and even go two->nth relationships deep. Something like this:
Name, Joe, Equals
Age, 35, Less Than
Jobs.Occupation, Geek, Equals
Jobs.Occupation.Salary.Rate, 1000, Greater Than
I have no problem writing the LINQ query by hand:
var results = from m in DataContext.MessageType
where m.Name == "Joe"
& m.Age == 35
& m.Jobs.Occupation == "Geek"
& m.Jobs.Occupation.Salaray.Rate >= 1000
select m;
Any pointers how I can dynamically create this query? Any help is greatly appreciated. Thanks.
Eric S.
Note the use of expanding PropertyAccess.
{
BinaryExpression expression = null;
ParameterExpression parameter = Expression.Parameter(typeof(DataContext.Table), "p");
string columns = "Relation1.Relation2.Column1";
string value = "ABC123";
BinaryExpression exp = MakeQueryFilter(typeof(DataContext.Table), columns,value,'Equal', parameter);
expression = expression == null ? exp : Expression.AndAlso(expression, exp);
results = DataContext.Table.Where(Expression.Lambda<Func<Table, bool>>(expression, parameter));
}
public static BinaryExpression MakeQueryFilter(Type type, string propertyNames, object value, string dataoperator, ParameterExpression parameter)
{
string[] acolumns = columns.Split('.');
var property = typeof (MediaEvent).GetProperty(acolumns[0]);
MemberExpression propertyAccess = Expression.MakeMemberAccess(parameter, property);
Type propertyType = property.PropertyType;
if ((propertyType.IsGenericType) && (propertyType.GetGenericTypeDefinition() == typeof(Nullable)))
propertyType = propertyType.GetGenericArguments()[0];
if (acolumns.Length > 1)
{
for (int i = 1; i < acolumns.Length; i++)
{
propertyAccess = Expression.MakeMemberAccess(propertyAccess, propertyAccess.Type.GetProperty(acolumns[i]));
}
}
object queryvalue = null;
// convert the value appropriately
if (propertyType == typeof(System.Int32))
queryvalue = Convert.ToInt32(value);
if (property.PropertyType == typeof(DateTime))
queryvalue = Convert.ToDateTime(value);
if (property.PropertyType == typeof(Double))
queryvalue = Convert.ToDouble(value);
if (property.PropertyType == typeof(String))
queryvalue = Convert.ToString(value);
if (property.PropertyType == typeof(Guid))
queryvalue = new Guid(value.ToString());
var constantValue = Expression.Constant(queryvalue);
Type[] types = new Type[2];
types.SetValue(typeof(Expression), 0);
types.SetValue(typeof(Expression), 1);
var methodInfo = typeof(Expression).GetMethod(dataoperator, types);
var equality2 = (BinaryExpression)methodInfo.Invoke(null, new object[] { propertyAccess, constantValue });
return equality2;
}
I had the same issue. Thanks for the answer! Very useful!
You wrote this:
caller
{
BinaryExpression expression = null;
ParameterExpression parameter = Expression.Parameter(typeof(DataContext.Table), "p");
string columns = "Relation1.Relation2.Column1";
string value = "ABC123";
BinaryExpression exp
= MakeQueryFilter(typeof(DataContext.Table),
columns,value,'Equal', parameter);
expression = expression == null ? exp : Expression.AndAlso(expression, exp);
results = DataContext.Table.Where(
Expression.Lambda<Func<Table, bool>>(expression, parameter));
}
public static BinaryExpression MakeQueryFilter(Type type, string propertyNames, object value, string dataoperator, ParameterExpression parameter)
{
string[] acolumns = columns.Split('.');
var property = typeof (MediaEvent).GetProperty(acolumns[0]);
MemberExpression propertyAccess = Expression.MakeMemberAccess(parameter, property);
Type propertyType = property.PropertyType;
if ((propertyType.IsGenericType) && (propertyType.GetGenericTypeDefinition() == typeof(Nullable)))
propertyType = propertyType.GetGenericArguments()[0];
if (acolumns.Length > 1)
{
for (int i = 1; i < acolumns.Length; i++)
{
propertyAccess = Expression.MakeMemberAccess(propertyAccess, propertyAccess.Type.GetProperty(acolumns[i]));
}
}
object queryvalue = null;
// convert the value appropriately
if (propertyType == typeof(System.Int32))
queryvalue = Convert.ToInt32(value);
if (property.PropertyType == typeof(DateTime))
queryvalue = Convert.ToDateTime(value);
if (property.PropertyType == typeof(Double))
queryvalue = Convert.ToDouble(value);
if (property.PropertyType == typeof(String))
queryvalue = Convert.ToString(value);
if (property.PropertyType == typeof(Guid))
queryvalue = new Guid(value.ToString());
var constantValue = Expression.Constant(queryvalue);
Type[] types = new Type[2];
types.SetValue(typeof(Expression), 0);
types.SetValue(typeof(Expression), 1);
var methodInfo = typeof(Expression).GetMethod(dataoperator, types);
var equality2 = (BinaryExpression)methodInfo.Invoke(null, new object[] { propertyAccess, constantValue });
return equality2;
}
Maybe better if you write this:
public static BinaryExpression MakeQueryFilter<T>(string propertyNames, object value, string dataoperator, ParameterExpression parameter) where T : class
{
string[] props = propertyNames.Split('.');
var property = typeof(T).GetProperty(props[0]);
MemberExpression propertyAccess = Expression.MakeMemberAccess(parameter, property);
if (props.Length > 1)
{
for (int i = 1; i < props.Length; i++)
{
property = propertyAccess.Type.GetProperty(props[i]);
propertyAccess = Expression.MakeMemberAccess(propertyAccess, property);
}
}
Type propertyType = property.PropertyType;
if ((propertyType.IsGenericType) && (propertyType.GetGenericTypeDefinition() == typeof(Nullable)))
propertyType = propertyType.GetGenericArguments()[0];
object queryvalue = null;
// convert the value appropriately
if (propertyType == typeof(System.Int32))
queryvalue = Convert.ToInt32(value);
if (property.PropertyType == typeof(DateTime))
queryvalue = Convert.ToDateTime(value);
if (property.PropertyType == typeof(Double))
queryvalue = Convert.ToDouble(value);
if (property.PropertyType == typeof(String))
queryvalue = Convert.ToString(value);
if (property.PropertyType == typeof(Guid))
queryvalue = new Guid(value.ToString());
var constantValue = Expression.Constant(queryvalue);
Type[] types = new Type[2];
types.SetValue(typeof(Expression), 0);
types.SetValue(typeof(Expression), 1);
var methodInfo = typeof(Expression).GetMethod(dataoperator, types);
var equality2 = (BinaryExpression)methodInfo.Invoke(null, new object[] { propertyAccess, constantValue });
return equality2;
}
While working on a personal project I wanted a simple service to extract items out of Outlook and host in WCF in a "RESTful" design. In the process I came up with this rather beastly class.
What other scary linq code have people have seen?
public IQueryable<_AppointmentItem> GetAppointments(DateTime date)
{
var dayFlag = (OlDaysOfWeek)(int)Math.Pow(2, (int)date.DayOfWeek);
return
OlDefaultFolders.olFolderCalendar.GetItems<_AppointmentItem>()
.Select(a => new
{
Appointment = a,
RecurrencePattern = a.IsRecurring ?
a.GetRecurrencePattern() : null
})
.Where(a =>
a.Appointment.Start.Date <= date &&
(
(a.RecurrencePattern == null &&
a.Appointment.End.Date >= date) ||
(
a.RecurrencePattern != null &&
(
(a.RecurrencePattern.DayOfMonth == 0 ||
a.RecurrencePattern.DayOfMonth == date.Day) &&
(a.RecurrencePattern.DayOfWeekMask == 0 ||
((a.RecurrencePattern.DayOfWeekMask &
dayFlag) != 0)) &&
(a.RecurrencePattern.MonthOfYear == 0 ||
a.RecurrencePattern.MonthOfYear == date.Month)
)
)
)
)
.Select(a => a.Appointment);
}
[OperationContract()]
[WebGet(
UriTemplate = "/appointments/{year}/{month}/{day}",
RequestFormat = WebMessageFormat.Xml,
ResponseFormat = WebMessageFormat.Xml,
BodyStyle = WebMessageBodyStyle.Bare
)]
[ContentType("text/xml")]
public XElement ListAppointments(string year, string month, string day)
{
try
{
int iYear, iMonth, iDay;
int.TryParse(year, out iYear);
int.TryParse(month, out iMonth);
int.TryParse(day, out iDay);
if (iYear == 0) iYear = DateTime.Now.Year;
if (iMonth == 0) iMonth = DateTime.Now.Month;
if (iDay == 0) iDay = DateTime.Now.Day;
var now = new DateTime(iYear, iMonth, iDay).Date; // DateTime.Now;
return GetAppointments(now).ToXml();
}
catch (System.Exception ex)
{
return new XElement("exception", ex.ToString());
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Microsoft.Office.Interop.Outlook;
namespace WhitedUS.ServiceModel.Office.Linq
{
public static class OutlookUtilities
{
public static IQueryable<T> GetItems<T>(
this OlDefaultFolders defaultFolderType)
{
return
new ApplicationClass()
.Session
.GetDefaultFolder(defaultFolderType)
.Items
.OfType<T>()
.AsQueryable();
}
public static XElement ToXml<T>(this IEnumerable<T> input)
{
if (input == null)
return null;
Type typ = typeof(T);
var root = XName.Get(typ.Name.Trim('_'));
return new XElement(root,
input
.Select(x => x.ToXml<T>())
.Where(x => x != null)
);
}
public static XElement ToXml<T>(this object input)
{
if (input == null)
return null;
Type typ = typeof(T);
var root = XName.Get(typ.Name.Trim('_'));
return new XElement(root,
typ.GetProperties()
.Where(p => p.PropertyType.IsValueType ||
p.PropertyType == typeof(string))
.Select(p => new { Prop = p, Getter = p.GetGetMethod() })
.Where(p => p.Getter != null)
.Select(p => new { Prop = p.Prop, Getter = p.Getter,
Params = p.Getter.GetParameters() })
.Where(p => (p.Params == null || p.Params.Count() <= 0))
.Select(p => new { Name = p.Prop.Name,
Value = p.Getter.Invoke(input, null) })
.Where(p => p.Value != null)
.Select(p => new XAttribute(XName.Get(p.Name), p.Value))
);
}
}
}
Also see: What is the worst abuse you’ve seen of LINQ syntax?
A fully LINQified RayTracer is pretty scary.
Actually, the scariest Linq query I ever saw was my first one. It was just familiar enough to make me think I understood it and just different enough to make me doubt that I really did.