get delegate does not take 1 argument error when using linq - c#

i am trying to add the statement after i form the linq statement. However, i get this error after i verified the code is correct. Why it cause the error?
query3 = query3.Where(a => a.product_group_id.Contains(1));
i added the using System.Linq.Dynamic; on the top.

Try:
var query3 = query3.Where(a => a.product_group_id == 1).Select(i=>i).ToList();
.Where() returns IEnumerable. You can't mix Contains with Where, since the first returns bool, not int.
Try .Any() if you want to check if db has the element with specified condition.
bool query3 = query3.Any(a => a.product_group_id == 1);
.Contains() returns bool. It only check if the OBJECT exists.
bool query3 = query3.Contains(yourProduct);

Related

Cannot convert string to int32 LINQ

I have code like this:
foreach (DataRow row in tmpDatosModulos.Rows)
{
tmpBSCID += row["ModuloURL"].ToString();
tmpBSCID = tmpBSCID.Replace("../BSC/wf_BSC_Reporte.aspx?BSCID=", "");
}
bsc = _c.ConfiguracionesBalance.Where(x => x.mdEstatusRegistro && x.sEstatus.Equals("A") && x.ID == int.Parse(tmpBSCID)).ToList();
I get error when I debbug it:
LINQ to Entities does not recognize the method 'Int32
Parse(System.String)' method, and this method cannot be translated
into a store expression.
I read another questions about that, and solution explained is to parse outside LINQ expression so I do something like this:
foreach (DataRow row in tmpDatosModulos.Rows)
{
tmpBSCID += row["ModuloURL"].ToString();
tmpBSCID = tmpBSCID.Replace("../BSC/wf_BSC_Reporte.aspx?BSCID=", "");
}
tmpBSCID = int.Parse(tmpBSCID);
bsc = _c.ConfiguracionesBalance.Where(x => x.mdEstatusRegistro && x.sEstatus.Equals("A") && x.ID == tmpBSCID).ToList();
but I get
Cannot implicity convert int to string
in this line tmpBSCID = int.Parse(tmpBSCID);
It's a little confussing because I'm converting string to int and no viceversa. Regards
What kind of type is your variable "tmpBSCID"? From the code you poste seems it's a string, and in the part
tmpBSCID = int.Parse(tmpBSCID);
you are assigning a int field to a string variable. If you need to keep using tmpBSCID, after the parsing method use the "ToString()", otherwise you can create a new int variable (or var).
I would rewrite it as
var tmpBSCIDValue = int.Parse(tmpBSCID);
bsc = _c.ConfiguracionesBalance.Where(x => x.mdEstatusRegistro && x.sEstatus.Equals("A") && x.ID == tmpBSCIDValue).ToList();
You need to assign a new variable (of type integer) to the result of your parsed string, and applying the integral variable to your LINQ query, i.e.:
var myIntegerBSCID = int.Parse(tmpBSCID);
bsc = _c.ConfiguracionesBalance
.Where(x => x.mdEstatusRegistro && x.sEstatus.Equals("A") && x.ID == myIntegerBSCID)
.ToList();
Other than dynamic, C# will not allow you to change the type of an existing variable, i.e.
tmpBSCID = int.Parse(tmpBSCID);
can't work, because the LHS type would need to be Integral, whereas the original RHS type of tmpBSCID is of course string.
As an aside, consider using a StringBuilder to build up tmpBSCID rather than looping and concatenating strings.
And finally, you might also consider the case where tmpBSCID cannot be parsed as an integer. You can use int.TryParse(out var myIntegerBSCID) as an alternative - it returns false if the parse fails.
From your code (+=) I conclude what you're trying to do is: collect a list of ID values from a data table, not just one single ID. So you have to build this list and then use Contains in the LINQ query:
var idValues = tmpDatosModulos.Rows.Select(row =>
{
tmpBSCID = row["ModuloURL"].ToString()
.Replace("../BSC/wf_BSC_Reporte.aspx?BSCID=", "");
return int.Parse(tmpBSCID);
}).ToList();
bsc = _c.ConfiguracionesBalance
.Where(x => x.mdEstatusRegistro && x.sEstatus.Equals("A")
&& idValues.Contains(x.ID)).ToList();
Side note: you seem to be confident that int.Parse always succeeds. I'd prefer using int.TryParse.
Althoug LINQ does not recognize int.Parse() you can do bsc = _c.ConfiguracionesBalance.Where(x => x.mdEstatusRegistro && x.sEstatus.Equals("A") && x.ID == (int)(tmpBSCID)).ToList(); to force the conversion.
Looking at your first error, I gather that _c.ConfiguracionesBalance is an IQueryable.
IQueryables are different that IEnumerables in the fact that an IQueryable doesn't hold the code to create an Enumerator for your sequence. It holds an Expression and a Provider. The Provider knows who should perform the Expression (usually an external process like a database). The provide also knows the language this external process speaks (for example SQL). The provider knows how to translate the Expression into this language.
As soon as you want to access the first element of the sequence represented by your IQueryable, the IEnumerator for this sequence is fetched from the IQueryable. The expression is sent to the Provider who translates it into the language for the other process and orders this other process to perform the query.
This provider can't translate your own functions into SQL. In fact, although there are a lot of .NET functions that can be translated, there is a list of supported and not supported LINQ functions
In this list you can see that Int32.Parse is not supported. Therefore it was wise to parse locally.
You don't write the type of tmpBSCID, but from your statements I gather that it is a string. If you'd written the type, you'd already answered the questioin for yourself:
string tmpBSCID += row["ModuloURL"].ToString(); // from your code
tmpBSCID = Int32.Parse(tmpBSCID);
And you wonder why the compiler complains that it can't convert the int to a string?

Linq Where clause not returning what I expect when performing String.Contains(String) on a null string

I scratched my head for one hour on this yesterday with no results but sweat.
string SearchTag = "";
Extension.getDBService<MyClass>().FindAll(i => <true condition>);
This returned me all my MyClass DB records as I would expect.
string SearchTag = "";
Extension.getDBService<MyClass>().FindAll(i => <true condition> && i.TAG.ToLower().Trim().Contains(SearchTag.ToLower().Trim()));
This returned a 0 Count collection!! I do not understand this.
string SearchTag = "e";
Extension.getDBService<MyClass>().FindAll(i => <true condition> && i.TAG.ToLower().Trim().Contains(SearchTag.ToLower().Trim()));
This returns a collection containing all MyClass DB records again. This is normal as i.TAG always contains "e".
Why do I get a 0 members collection with the second expression?
"string".Contains("") should always be true right?
PS: Extension.getDBService() is a call to a DBContext by the way.
Thx for your assistance.
Interestingly, the way you wrote the LINQ query generates SQL CHARINDEX(...) > 0 criteria which returns false for empty string.
However, if you remove (move outside the query) the ToLower().Trim() part of the SearchTag variable
SearchTag = SearchTag.ToLower().Trim();
and use
i.TAG.ToLower().Trim().Contains(SearchTag)
inside the LINQ query, then the generated SQL criteria is LIKE operator and works as expected.
Just another example that LINQ to Entities is not like LINQ to Objects.

Filter in linq with ID's in a List<int>

I need do a filter that request data with a parameter included in a list.
if (filter.Sc.Count > 0)
socios.Where(s => filter.Sc.Contains(s.ScID));
I try on this way but this not work, I tried also...
socios.Where( s => filter.Sc.All(f => f == s.ScID));
How I can do a filter like this?
socios.Where(s => filter.Sc.Contains(s.ScID));
returns a filtered query. It does not modify the query. You are ignoring the returned value. You need something like:
socios = socios.Where(s => filter.Sc.Contains(s.ScID));
but depending on the type of socios the exact syntax may be different.
In addition to needing to use the return value of your LINQ .Where(), you have a potential logic error in your second statement. The equivalent logic for a .Contains() is checking if Any of the elements pass the match criteria. In your case, the second statement would be
var filteredSocios = socios.Where( s => filter.Sc.Any(f => f == s.ScID));
Of course if you can compare object-to-object directly, the .Contains() is still adequate as long as you remember to use the return value.

Rewriting a Linq statement

Here is what I currently have:
from s in domainThreads.Values
where (s.IsAvailable)
select s;
but I'm still learning Linq and believe that I can get it all on one line. Does the following look correct?
domainThreads.Values.Where(s => s.IsAvailable).Any();
Do I need the .Any()?
Any() returns a boolean indicating whether or not there are any entities in the given set.
The equivalent of your original LINQ expression would simply be:
domainThreads.Values.Where(s => s.IsAvailable)
The two are not equivalent.
The first returns all Values where s.IsAvailable.
The second returns whether there are any such values.
A correct conversion is:
domainThreads.Values.Where(s => s.IsAvailable)
Which translates to:
domainThreads.Values.Where(s => s.IsAvailable).Select(s => s)
Which is what the original query gets transformed to anyways.
You don't need the Any() -- that will return a bool indicating if any of elements satisfy the condition.
Instead, just do:
domainThreads.Values.Where(s => s.IsAvailable)
domainThreads.Values.Where(s => s.IsAvailable)
is enough.
Any() returns a bool value, but your original query returns a data set. So just use Where()
var result = domainThreads.Values.Where(s => s.IsAvailable);
Any() would be helpful when you just need ensure that at least single item satisfies a condition
Try this
var obj = domainThreads.Values.Where(s => s.IsAvailable == true).Select(o => o);
If you call Any() it returns bool which indicates that you have at least one item.
domainThreads.Values.Where(s => s.IsAvailable);
this expression is enough and it is equivalent to the LINQ statement.
Any() returns a boolean that is true if the result contains one or more items.
var elements = from s in domainThreads.Values
where (s.IsAvailable)
select s;
//elements now contains a list of objects.
This is equivalent to:
elements = domainThreads.Where(s => s.IsAvailable);
It looks but is not the same. The result is boolean and returns true if the collection contains any elements.
You could write something like this, but is it really worth the effort?
var result = domainThreads.Values.Where(s => s.IsAvailable).Select(s => s);
or shorter:
var result = domainThreads.Values.Where(s => s.IsAvailable);
EDIT: if you just want to have one line of code you can also write:
from s in domainThreads.Values where s.IsAvailable select s;
It's much more readable and generates to the same code in the end.

convert IQueryable<int> to <int>

I want to select my price level in database to compare with the an integer number. But It is error : Operator '==' cannot be applied to operands of type 'System.Linq.IQueryable' and 'int'.
This is my code :
if (Request.IsAuthenticated){
CustomerModels cm = new CustomerModels();
string userName = Page.User.Identity.Name;
var list_pricelevel = from c in cm.DataContext.Customers
where c.WebAccount == userName
select c.PriceLevel;
if (list_pricelevel == 3) {
Response.Write("Welcome");
}
}
var list_pricelevel
This is per definition not an int because more than one row can be returned.
I don't use SQL syntax (only lambda) but at the end you want the equivalent of a .FirstOrDefault or Single or First. Basically taking the first row.
replace:
if (list_pricelevel == 3)
with:
if (list_pricelevel.First() == 3)
as you can see here: http://msdn.microsoft.com/en-us/library/bb291976.aspx, if you are sure there is a result or use FirstOrDefault...
when you have the result from LinQ expression you will always have the list of result set.
So in your code when you are querying as below :
var list_pricelevel = from c in cm.DataContext.Customers
where c.WebAccount == userName
select c.PriceLevel;
The list_pricelevel will be in the form of List ie IQueryable list,
so you have to get only one element to check with one element
so use the below code :
if (list_pricelevel.Single() == 3)
{
Response.Write("Welcome");
}
or
if (list_pricelevel.First() == 3)
{
Response.Write("Welcome");
}
both the above code gives you only one result set value so you can equate with 3 for validation.
Here is my suggestion:
if (list_pricelevel.First() == 3)
{
Response.Write("Welcome");
}
This may rise a NullReferenceException in case there is no item in Customers satisfying where c.WebAccount == userName.
Explanation:
list_pricelevel is a IEnumerable of items satisfying your where clause.
You need get the first item from your collection.
if (list_pricelevel.First() == 3) {
Response.Write("Welcome");
}
That's the beauty of Linq that every query returns an IQueryable so you can defer getting the final result until you really decided what you want. On the other word you can execute a query over another query :)
So in order to get the real data out of a query you should execute a command over it that actually returns what you want.
In your case since you are expecting your query to return only one value any methods like "FirstOrDefault","Single" or "First" will do the trick

Categories

Resources