I am trying to make search function in my project.
Currently, I want to convert decimal value to string for comparing with searchString.
When I put like this:
public ActionResult Search(string searchString)
{
var product = from a in _db.Product.Include(a => a.Category)
select a;
if (!String.IsNullOrEmpty(searchString))
{
product = product.Where(a => a.model.ToUpper().Contains(searchString.ToUpper())
|| Convert.ToInt32(a.displaySize).ToString().Contains(searchString));
}
return View(product.ToList());
}
It has error,
'LINQ to Entities does not recognize the method 'System.String
ToString()' method'.
How can I compare decimal value with string value?
Could you help me?
Thanks.
You can't use C# functions that can't be converted to SQL like .ToString(). You can use LINQ to Objects instead if your table isn't very large by calling .ToList() before Where
product = product.ToList().Where(a => a.model.ToUpper().Contains(searchString.ToUpper())
|| Convert.ToInt32(a.displaySize).ToString().Contains(searchString));
EDIT:
You can use functions from SqlFunctions namespace. that functions can easily be converted to SQL.
You could try converting your string value (query parameter) to a decimal and comparing the reverse.
It looks like you are searching for two different things. I would split this linq statment at the ||. If you are looking for whatever a.model is, go to one method, if you are looking for the int value go to another and convert the search string to an int BEFORE the linq statment. That method would like something like:
int searchInt;
if(int.TryParse(searchString, out searchInt))
{
product = product.Where(a => a.displaySize == searchInt);
}
You have to do this because SQL doesn't have a ToString() method... so LINQ doesn't really know what to do with it. Remember that this all gets converted to SQL.
Related
I am in the process of learning LINQ, ASP.NET, EF, and MVC via online video tutorials. I would love some help understanding Joins in LINQ extension method syntax.
For simplification, I have two tables (these map to a SQL DB):
User Table:
public int userID{get;set;}
public string firstName{get;set;}
...
Address
public int ownerID{get;set;}
public int value{get;set;}
public string Nickname{get;set;}
public string street{get;set;}
public string zip{get;set;}
...
Let's say I want to find all the property that a particular user owns. I believe I can do something like this:
var test = db.User
.Join(db.Address, user => user.userID, add => add.ownerID, (user, add) => new { user, add });
Source: http://byatool.com/c/linq-join-method-and-how-to-use-it/
This should be equivalent to
SELECT * FROM User a JOIN Address b on a.userID = b.ownerID
Please confirm that this is correct.
Now, what if I wanted to find all property that a particular user owns that has a value greater than x. Let's take it a step further and say x is a result from another LINQ query. How do I force execution of x inside of a second query? Do I even have to consider this, or will LINQ know what to do in this case?
Thanks
EDIT:
When I try to use the result of a query as a parameter in another, I am required to use a greedy operator to force execution. Many people like to use .Count() or .ToList(). I only expect x (from example above) to return 1 string by using .Take(1). If I append ToList() to the end of my first query, I am required to use x[0] in my second query. This seems like a messy way to do things. Is there a better way to force execution of a query when you know you will only have 1 result?
If I understand your question, you're trying to do a conditional on a joined model?
var query = db.Users.Where(x => x.Addresses.Where(y => y.Value >= yourValue).Any());
That will return all users who have a property value greater than yourValue. If you need to return the addresses with the query, you can just add Include to your query. For example:
query.Include(x => x.Addresses);
You don't need to manually do that Join that you have in your example.
I would like to concatenate a string using lambda to compare that concatenated value against a certain condition.
Invoices = Invoices.Where(f => ((string)f.invoice_prefix + String.Format("{0:0000}", Convert.ToInt32(f.invoice_number))).ToLower().Equals(condition7));
But I get an error message :
The name 'f' does not exist in the current context
Tried several String.Format and String.Concat variants like
Invoices = Invoices.Where(f => (String.Format("{0}{1}",f.invoice_prefix,String.Format("{0:0000}", Convert.ToInt32(f.invoice_number)))).ToLower().Equals(condition7));
but no success... Can somebody help me with the syntax?
Thanks in advance!
Linq to Entities doesn't understand all of the .NET framework methods.
In order to run this as a SQL statement on the database, you need to only use operators that can be converted to SQL. That means you need to re-write your predicate using primitive data types.
So something like this:
string prefixCondition = ...
int invoiceNumberCondition = ...
Invoices.Where( f =>
f.invoice_prefix == prefixCondition
&&
f.invoice_number == invoiceNumberCondition
)
I recommend using LinqPad to test with, as it shows you the generated SQL statement.
I have an extension method as follows:
public static bool SatisfiesSomeCondition(this Post post, SomeObj someObj)
{
return post.SomeObjId == someObj.SomeObjId;
}
And i'm trying to use it like this:
var query = ctx.Posts.Where(p => p.SatisfiesSomeCondition(someObj)).ToList();
But i get the error:
LINQ to Entities does not recognize the method 'Boolean SatisfiesSomeCondition(xx.xx.xx.Post, xx.xx.xx.SomeObj)' method, and this method cannot be translated into a store expression.
If i change the query to:
var query = ctx.Posts.Where(p => p.SomeObjId == someObj.SomeObjId).ToList();
Which is identical to the method.
It works fine, and executes the expected T-SQL.
Why doesn't my first query work? It's a static method, can't it figure out how to create the expression tree? (e.g a WHERE filter). Surely i don't have to materialize the query first? (which means the records i don't want come back over the wire, and i'm doing paging/ordering here, so that's not an option).
Of course, i can just go with what works (e.g the above), but the method SatisfiesSomeCondition is an existing method used across the domain and i want to re-use that functionality, not duplicate it.
Any ideas?
Change it to:
public static IQueryable<Post> SatisfiesSomeCondition(this IQueryable<Post> query, SomeObj someObj)
{
int id = someObj.SomeObjId;
return query.Where(post => post.SomeObjId == id);
}
and use it like:
var query = ctx.Posts.SatisfiesSomeCondition(someObj)).ToList();
This way it should work. You can combine multiple Where conditions in single query so it should offer you at least basic reusablity.
The LINQ to Entities engine has no way of knowing what your static method does.
LINQ queries can only be translated from expression trees.
Is there any chance to run c# method in linq query?
I need to do something like that:
//...
class Match {
public double PrecentageMatching(string s1, string s2) {
//...
return result; // value from 0.0 to 1.0
}
}
//...
string pattern = "nameOfRecord";
var similarRecords = db.Table.Select(
r => Match.PrecentageMatching(r.name, pattern) > 0.5
);
I know that there linq wont know a method PrecentageMatching. But I'm wonder if there is any way to do it?
I'm using Entity framework.
I need to do it without stored procedures and assembly on database side. I dont have access to database.
You first need to fetch the data from the database and only then perform the transformation:
string pattern = "nameOfRecord";
var similarRecords = db.Table
.Select(r => r.name)
.ToList() // This call fetches the data from the DB
.Select(x => Match.PrecentageMatching(x, pattern) > 0.5);
That's not a problem at all, because you are only transforming the returned data with your method. If you want to use your method to filter the returned data using Where, you have a problem, because you would first need to return ALL data and filter the data on your client. This might be a problem if the table is big.
Change your PrecentageMatching method to a static method. It will then be able to find Match.PrecentageMatching method.
Also, what you're doing there will return a IEnumerable of boolean values. If you want to return records from the Table, you want "Where" instead of "Select".
Edit: as per comments, you need to call ToList() method.
I have an enum called OrderStatus, and it contains various statuses that an Order can be in:
Created
Pending
Waiting
Valid
Active
Processed
Completed
What I want to do is create a LINQ statement that will tell me if the OrderStaus is Valid, Active, Processed or Completed.
Right now I have something like:
var status in Order.Status.WHERE(status =>
status.OrderStatus == OrderStatus.Valid ||
status.OrderStatus == OrderStatus.Active||
status.OrderStatus == OrderStatus.Processed||
status.OrderStatus == OrderStatus.Completed)
That works, but it's very "wordy". Is there a way to convert this to a Contains() statement and shorten it up a bit?
Sure:
var status in Order.Status.Where(status => new [] {
OrderStatus.Valid,
OrderStatus.Active,
OrderStatus.Processed,
OrderStatus.Completed
}.Contains(status.OrderStatus));
You could also define an extension method In() that would accept an object and a params array, and basically wraps the Contains function:
public static bool In<T>(this T theObject, params T[] collection)
{
return collection.Contains(theObject);
}
This allows you to specify the condition in a more SQL-ish way:
var status in Order.Status.Where(status =>
status.OrderCode.In(
OrderStatus.Valid,
OrderStatus.Active,
OrderStatus.Processed,
OrderStatus.Completed));
Understand that not all Linq providers like custom extension methods in their lambdas. NHibernate, for instance, won't correctly translate the In() function without additional coding to extend the expression parser, but Contains() works just fine. For Linq 2 Objects, no problems.
I have used this extension:
public static bool IsIn<T>(this T value, params T[] list)
{
return list.Contains(value);
}
You may use this as the condition:
Where(x => x.IsIn(OrderStatus.Valid, ... )
If that set of statuses has some meaning, for example those are statuses for accepted orders, you can define an extension method on your enum and use that in your linq query.
public static class OrderStatusExtensions
{
public static bool IsAccepted(this OrderStatuses status)
{
return status == OrderStatuses.Valid
|| status == OrderStatuses.Active
|| status == OrderStatuses.Processed
|| status == OrderStatuses.Completed;
}
}
var acceptedOrders = from o in orders
where o.Status.IsAccepted()
select o;
Even if you could not give the method a simple name, you could still use something like IsValidThroughCompleted. In either case, it seems to convey a little more meaning this way.
Assumnig that the enum is defined in the order you specified in the question, you could shorten this by using an integer comparison.
var result =
Order.Status.Where(x =>
(int)x >= (int)OrderStatus.Valid &
& (int)x <= (int)OrderStatus.Completed);
This type of comparison though can be considered flaky. A simply re-ordering of enumeration values would silently break this comparison. I would prefer to stick with the more wordy version and probably clean up it up by refactoring out the comparison to a separate method.
You could put these in a collection, and use:
OrderStatus searchStatus = new[] {
OrderStatus.Valid,
OrderStatus.Active,
OrderStatus.Processed,
OrderStatus.Completed };
var results = Order.Status.Where(status => searchStatus.Contains(status));