how to use "not equal to" in where condition using linq with entity framework - entity-framework

how to use "not equal to" in where condition using LINQ with entity framework.
public ActionResult ViewOfficeType()
{
return View(entity.TBL_OFFICETYPE.Where(p => p.STATUS<>"D").ToList());
}
it shows invalid expression '>'
if i use '!='.It doesn't show error.But it doesn't work.

you can use the ! operator on Equals()
public ActionResult ViewOfficeType()
{
return View(entity.TBL_OFFICETYPE.Where(p => !p.Equals("D")).ToList());
}

You can you use the following approaches
Use != operator in you lambda expression
public ActionResult ViewOfficeType()
{
return View(entity.TBL_OFFICETYPE.Where(p => p.STATUS != "D").ToList());
}
Use !string.Equals
public ActionResult ViewOfficeType()
{
return View(entity.TBL_OFFICETYPE.Where(p => !p.STATUS.Equals("D")).ToList());
}
Note: Be aware of string comparison issues like character encoding, and case sensitivity etc.

I would prefer a Extension method as follows:
public static class StringExtension
{
public static bool NotEquals(this string source, string target)
{
return !(source.Equals(target));
}
}
How it works:
string source = "Test"; // Sample / Source data
// Tested with "test", result is true, since the case is different, so two strings are different
source.NotEquals("test");
// Tested with "Test", result is false, since they are same
source.NotEquals("Test");
Lot more things are possible inside the extension method, based on whether you want to ignore the case, you can simply pass StringComparison.OrdinalIgnoreCase in the Equals method, then "Test" will be evaluated equal to "test" (case ignored)

var status = entity.TBL_OFFICETYPE.Select(p => p.STATUS == "D");
return View(entity.TBL_OFFICETYPE.Where(p => !status.Contains(p.STATUS == "D")).ToList());
plz try this

Related

How to specify a default Sort with Hotchocolate and EF Core?

Is there a way to add a Default Sort field, so that I can UsePaging and UserSorting, but if no order is specified I add a field, such as Id. But if the user does specify an order, then don't add the default.
For example, I can add the default sort to the query method, but then no other sorting works
[UseContext]
[UsePaging]
[UseProjection]
[UseFiltering]
[UseSorting]
public IQueryable<Property> GetProperties([ScopedService] PropContext dbContext)
{
return dbContext.Properties
.OrderBy(p => p.Id); // Default sort by Prop Id
}
If don't have a sort, then Entity Framework shows a warning:
The query uses a row limiting operator ('Skip'/'Take') without an 'OrderBy' operator.
This may lead to unpredictable results
And I've seen some unexpected results
Credit to S Blomstrand
Using these extension methods
public static bool HasOrderByArgument(this IResolverContext context,
string argumentName = "order")
{
try
{
var orderByArgument = context.ArgumentLiteral<IValueNode>(argumentName);
if (orderByArgument != NullValueNode.Default && orderByArgument != null)
{
return true;
}
}
catch
{
return false;
}
return false;
}
public static IQueryable<T> OrderByArgumentOrDefault<T>(this IQueryable<T> query, IResolverContext context,
Func<IQueryable<T>> func, string argumentName = "order")
{
if (context.HasOrderByArgument(argumentName))
{
return query;
}
return func.Invoke();
}
It can then be call as follows:
[UseContext]
[UsePaging]
[UseProjection]
[UseFiltering]
[UseSorting]
public IQueryable<Property> GetProperties([ScopedService] PropContext dbContext)
{
return dbContext.Properties
.OrderByArgumentOrDefault(context, () => properties.OrderBy(p => p.Id));
}
the Kerr/Blomstrand answer to this question didn't quite work for me as written
The following changes did work:
you need an IResolverContext argument in the query method (the runtime will fill it, no attribute needed)
change the Func to an Expression
public static IQueryable<T> OrderByArgumentOrDefault<T>(
this IQueryable<T> query,
IResolverContext context,
Expression<Func<IQueryable<T>>> expression,
string argumentName = "order")
{
return context.HasOrderByArgument(argumentName) ? query : expression.Compile().Invoke();
}
public IQueryable<Property> GetProperties(
[ScopedService] PropContext dbContext,
IResolverContext context)
{
return dbContext.Properties
.OrderByArgumentOrDefault(context, () => dbContext.Properties.OrderBy(p => p.Id));
}

Unable to cast the type 'System.Int32' to type 'System.Object during EF Code First Orderby Function

I'm using Specification pattern in EF Code First. When I do order by operation, VS throw a new exception
The specification pattern is copy from eShopOnWeb
I just change a little bit, here is my change code:
public class Specification<T> : ISpecification<T>
{
public Expression<Func<T, object>> OrderBy { get; private set; }
public Specification(Expression<Func<T, bool>> criteria)
{
Criteria = criteria;
}
public Specification<T> OrderByFunc(Expression<Func<T, object>> orderByExpression)
{
OrderBy = orderByExpression;
return this;
}
}
Here is my invoke code, it's very pretty simple:
static void TestSpec()
{
var spec = new Specification<ExcelData>(x => x.RowIndex == 5)
.OrderByFunc(x => x.ColumnIndex);
using (var dbContext = new TechDbContext())
{
var top10Data = dbContext.ExcelData.Take(10).ToList();
var listExcel = dbContext.ApplySpecification(spec).ToList();
Console.WriteLine();
}
}
If I comment OrderByFunc, then everything is fine to me. no error throw from vs.
I had try many times search the error message in google, but none of answer is my case.
So I have to ask a question in here.
When I debug OrderBy property in SpecificationEvaluator.cs, I found there is a Convert method.
So I know the error is about cast error, but how do I fix this cast type error?
Please help me!
The solution is to create new lambda expression with cast (Convert) removed, and then use it to call the Queryable class OrderBy / OrderByDescending method either dynamically (using DLR dispatch or reflection) or by emitting Expression.Call to it.
For the first part, add the following helper method to the SpecificationEvaluator class:
static LambdaExpression RemoveConvert(LambdaExpression source)
{
var body = source.Body;
while (body.NodeType == ExpressionType.Convert)
body = ((UnaryExpression)body).Operand;
return Expression.Lambda(body, source.Parameters);
}
Then replace the code
query = query.OrderBy(specification.OrderBy);
with either
query = Queryable.OrderBy((dynamic)query, (dynamic)RemoveConvert(specification.OrderBy));
or
var keySelector = RemoveConvert(specification.OrderBy);
query = query.Provider.CreateQuery<T>(Expression.Call(
typeof(Queryable), nameof(Queryable.OrderBy),
new[] { typeof(T), keySelector.ReturnType },
query.Expression, keySelector));
Do similar for the specification.OrderByDescending.

Linq Expression building for Entity Framework involving complex object

I am using Entity Framework version 4. I need to compare a large (~1 million record) SQL Server table to a longish (~2000) array of complex objects returned from a web service. Five different properties need to be compared to determine whether an instance of the complex object is already in the database.
I created a function that returns an expression for use in .Where and .Any methods. It looks like this (where A is the complex object, and tblA is the EF class):
function Expression<tblA, bool> GetSearchPredicate(A a)
{
return ta => ta.Field1.Equals(a.Field1)
&& ta.Field2.Equals(a.Field2)
&& ta.Field3.Equals(a.Field3)
&& ta.Field4.Equals(a.Field4)
&& ta.Field5.Equals(a.Field5);
}
This works. And I can compare all 2000 instances of A by doing this:
IEnumerable<A> objects = [web service call];
var result = objects.Select(a => !db.tblA.Any(GetSearchPredicate(a)));
That works, too. But it's slow. So I looked into building a utility method that could build an expression that could be transmitted down to the database directly through EF.
I used the code in this question as a basis for building that utility method. The example in that question shows comparing a single property to a series of constants, while my version would have to compare multiple properties to multiple constants. My best effort is below:
public static IQueryable<TEntity> WhereIn<TEntity>
(
this ObjectQuery<TEntity> query,
IEnumerable<Expression<Func<TEntity, bool>>> predicates
)
{
if (predicates == null) throw new ArgumentNullException("predicates");
IEnumerable<ParameterExpression> p = predicates.Select(pred => pred.Parameters.Single()).ToArray();
IEnumerable<Expression> equals = predicates.Select(value =>
(Expression)value.Body);
Expression bigEqual = equals.Aggregate((accumulate, equal) =>
Expression.Or(accumulate, equal));
var result1 = Expression.Lambda<Func<TEntity, bool>>(bigEqual, p.First());
var result = query.Where(result1);
return result;
}
This would be invoked like this:
IEnumerable<A> objects = [web service call];
var result = db.tblA.WhereIn(objects.Select(a => GetSearchPredicate(a)));
What I get is a message saying that "ta" (the placeholder for the TEntity object) is not bound. I thought this was because I had multiple expressions (the variable predicates) being combined, and maybe this message was being thrown because I was only passing the parameter from the first of the predicates IEnumerable. But this happens even if predicates is one expression long.
I am reasonably sure, based on the method I linked to, that I could build an expression comparing each of the five properties to a constant (the values of A.Field1 through A.Field5), rather than passing in the parameter predicates that already has them assembled into a series of expressions. But I would rather not, since that would require my method to know that it's working with types A and tblA, and that's the opposite of generic and general-purpose. (It'd also be complex and messy.)
I hope the examples I've shown explain what I want to do. Can it be done in a generic way?
You will need to replace the parameter in the predicate bodies with a single parameter. Something like this should work:
public static Expression<Func<T, bool>> BuildOr<T>(
IEnumerable<Expression<Func<T, bool>>> predicates)
{
Expression body = null;
ParameterExpression p = null;
Expression<Func<T, bool>> first = null;
foreach (Expression<Func<T, bool>> item in predicates)
{
if (first == null)
{
first = item;
}
else
{
if (body == null)
{
body = first.Body;
p = first.Parameters[0];
}
var toReplace = item.Parameters[0];
var itemBody = ReplacementVisitor.Transform(item, toReplace, p);
body = Expression.OrElse(body, itemBody);
}
}
if (first == null)
{
throw new ArgumentException("Sequence contains no elements.", "predicates");
}
return (body == null) ? first : Expression.Lambda<Func<T, bool>>(body, p);
}
private sealed class ReplacementVisitor : ExpressionVisitor
{
private IList<ParameterExpression> SourceParameters { get; set; }
private Expression ToFind { get; set; }
private Expression ReplaceWith { get; set; }
public static Expression Transform(
LambdaExpression source,
Expression toFind,
Expression replaceWith)
{
var visitor = new ReplacementVisitor
{
SourceParameters = source.Parameters,
ToFind = toFind,
ReplaceWith = replaceWith,
};
return visitor.Visit(source.Body);
}
private Expression ReplaceNode(Expression node)
{
return (node == ToFind) ? ReplaceWith : node;
}
protected override Expression VisitConstant(ConstantExpression node)
{
return ReplaceNode(node);
}
protected override Expression VisitBinary(BinaryExpression node)
{
var result = ReplaceNode(node);
if (result == node) result = base.VisitBinary(node);
return result;
}
protected override Expression VisitParameter(ParameterExpression node)
{
if (SourceParameters.Contains(node)) return ReplaceNode(node);
return SourceParameters.FirstOrDefault(p => p.Name == node.Name) ?? node;
}
}
Your WhereIn method then becomes:
public static IQueryable<TEntity> WhereIn<TEntity>(
this ObjectQuery<TEntity> query,
IEnumerable<Expression<Func<TEntity, bool>>> predicates)
{
if (predicates == null) throw new ArgumentNullException("predicates");
var predicate = BuildOr(predicates);
return query.Where(predicate);
}

IEnumerable - my extension method

public static Record FindOrCreate(this IEnumerable<Record> ienumerable, string name)
{
if (ienumerable.Where(element => element.Name == name).FirstOrDefault() != null)
return ienumerable.Where(element => element.Name == name).FirstOrDefault();
else
{
IEnumerable<Record> result = ienumerable.Concat(new[] {new Record(name, "")});
ienumerable = result;
return ienumerable.Where(element => element.Name == name).FirstOrDefault();
}
}
I know there is no Add method to IEnumerable but I want to stay with IEnumerable instead of ICollection and in really rare cases I have to add something. My methodmalways returns null if it doesn't find element.
Code EDITED !
So, now result has all elements that I want, but method still return null object. I don't know if is it possible to switch objects in extension methods? (like I did ienumerable=result) ?
I think you're trying to bend the IEnumerable<T> beyond it's purpose.
An IEnumerable<T> is just a sequence of elements and that's why IEnumerable<T> does not have an Add<T> method in it's interface. It's read only.
I would recommend changing your implementation of your extension method.
So the question is "how can I modify the code to not return null if the element isn't found, but return a new item"?
public static Record FindOrCreate(this IEnumerable<Record> source, string name)
{
Func<Record,bool> pred = element => element.Name == name;
return source.Any(pred) ? source.FirstOrDefault(pred) : new Record(name, "");
}
or
public static Record FindOrCreate(this IEnumerable<Record> source, string name)
{
return source.FirstOrDefault(element => element.Name == name) ?? new Record(name, "");
}
If the question is "how can I add a new item to the IEnumerable<Record> source, the short answer is you can't. The longer answer is cast the source to an ICollection and then add it. But at that point, you may as well just specify that you need an ICollection<T>
Note, I don't mean "you shouldn't" when I say "you can't", really, IEnumberable has no way to add items. Think about what it means to try to add a new number to the following seq
public IEnumerable<int> ShortSeq()
{
yield return 0;
}
var seq = ShortSeq();

LINQ to Entities - cannot cast 'System.DateTime' to type 'System.Object' in orderBy

I am trying to order an IQueryable of entities by date from a passed in Expression< Func< T, object>> and am getting the error: "Unable to cast the type 'System.Nullable`1' to type 'System.Object'. LINQ to Entities only supports casting Entity Data Model primitive types." The entity has a nullable datetime property on it on which I am trying to sort:
Example: (where e.Date is a nullable DateTime)
Expression<Func<T,object>> sorter = (e) => e.Date;
IOrderedQueryable<T> sortedData = data.OrderBy(sorter);
Thanks in advance!
I wrote a simple class for ordering entities based on a lambda expression at runtime.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
namespace DataModeling
{
public class QueryOrderer<TEntity>
where TEntity : class
{
private LambdaExpression defaultSortExpression;
private Dictionary<string, LambdaExpression> orderFieldLookup;
public QueryOrderer()
{
orderFieldLookup = new Dictionary<string, LambdaExpression>();
}
public void AddOrderMapping<TProp>(string fieldName, Expression<Func<TEntity, TProp>> selector)
{
orderFieldLookup[fieldName] = selector;
}
public void SetDefaultSortExpression<TProp>(Expression<Func<TEntity, TProp>> selector)
{
defaultSortExpression = selector;
}
public IQueryable<TEntity> GetOrderedEntries(string field, bool isDescending, IQueryable<TEntity> entries)
{
return orderEntries(entries, field, isDescending);
}
private IQueryable<TEntity> orderEntries(IQueryable<TEntity> entries, string fieldName, bool isDescending)
{
dynamic lambda = getOrderByLambda(entries, fieldName);
if (lambda == null)
{
return entries;
}
if (isDescending)
{
return Queryable.OrderByDescending(entries, lambda);
}
else
{
return Queryable.OrderBy(entries, lambda);
}
}
private dynamic getOrderByLambda(IQueryable<TEntity> entries, string fieldName)
{
if (!String.IsNullOrWhiteSpace(fieldName) && orderFieldLookup.ContainsKey(fieldName))
{
return orderFieldLookup[fieldName];
}
else
{
return defaultSortExpression;
}
}
}
}
You use this class by initially setting up all of the fields:
QueryOrderer<User> orderer = new QueryOrderer<User>();
orderer.SetDefaultSortExpression(u => u.FullName);
orderer.AddOrderMapping("UserId", u => u.UserId);
orderer.AddOrderMapping("Name", u => u.FullName);
orderer.AddOrderMapping("Email", u => u.Email);
orderer.AddOrderMapping("CreatedOn", u => u.CreatedOn);
...
var users = orderer.GetOrderedEntries("CreatedOn", isDescending: false, context.Users);
I nice feature of this code is that it handles look-up values perfectly. For instance, if you're trying to sort using the description rather than a key, you can use the outer context when building up the sort expression:
orderer.AddOrderMapping("UserType",
u => context.UserTypes
.Where(t => t.UserTypeId == u.UserTypeId)
.Select(t => t.Description)
.FirstOrDefault());
Entity Framework is smart enough to just fold the sub-query right into the outer query.
Two problem here: First you use object in your sorter, you should use DateTime. Secondly every element must have a place in the order so you have to define what should happen with elements where Date is null:
Expression<Func<T, DateTime>> sorter = (e) => e.Date ?? DateTime.MaxValue;
IOrderedQueryable<T> sortedData = data.OrderBy(sorter);
Try to reconstruct expression body
private LambdaExpression CreateLambdaPropertyGetter(Expression<Func<TEntity, object>> expression)
{
Expression body;
if (expression.Body is UnaryExpression && ((UnaryExpression)expression.Body).NodeType == ExpressionType.Convert)
body = ((UnaryExpression)expression.Body).Operand;
else
body = expression.Body;
var lambda = Expression.Lambda(body, expression.Parameters);
return lambda;
}
Try using Func delegate instead on Expression<Func>
Func<T,object> sorter = (e) => e.Date;
IOrderedEnumerable<T> sortedData = data.OrderBy(sorter);