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?
Related
My issue started off trying to find a case sensitive comparison to use with NHibernate.
public List<MessageLog> GetLogsByFileAndEventName (string fileName, string eventName, DateTime? after,
DateTime? before)
{
var query = m_session.QueryOver<Log> ()
.Where (x => x.CreatedOn >= after && x.CreatedOn <= before);
if (fileName != null)
(2) query = query.Where (x => x.FileName.Equals (fileName));
if (eventName != null)
(3) query = query.Where (x => x.LogRecords.Any (y => y.Event.Name.Equals (eventName)));
return query.List<Log>().ToList();
}
I have now replaced line 2 with
query = query.Where (Expression.Sql (" FileName = ? COLLATE Latin1_General_CS_AS", fileName, NHibernateUtil.String));
which yields a case sensitive comparison. I'm trying to use similar behavior when comparing event names(line 3), however this causes a mismatch with the arguments.
Edit: I've tried
query = query.Where (x => x.Records.Any(Expression.Sql (" SomeEvent.Name = ? COLLATE Latin1_General_CS_AS", eventName, NHibernateUtil.String)));
This results in "Argument type 'Nhibernate.Criterion.AbstractCriterion' is not assignable to parameter type 'System.Func<projectname.Dir.Nhibernate.Logs.LogRecord, bool>'
I've tried a couple other ways with linq(I'm fairly new to it) that don't yield the results that I want prior to case comparison.
My Question:
What would be the best way to check for case sensitivity on event name in line 3?
You are using the QueryOver API, which is not a linq API. It can use lambda expression as linq, but it is not linq.
I was believing you were having an exception, but you have a compilation error instead. You cannot combine NHibernate criterion (Expression.Sql yields a criterion) with linq methods (Any is a linq method, whereas in your code query.Where is a QueryOver method).
If you want to use linq, you should use linq-to-nhibernate instead.
using NHibernate.Linq;
...
var query = m_session.Query<Log>();
As far as I know, specifying collation is not supported in linq-to-nibernate. But you may extend it, as shown for another need here or here.
If you want to use QueryOver, using linq subqueries (the Any) does not look to me as the way subqueries are supposed to be expressed with QueryOver. I am not familiar with QueryOver, you should sort out how to express your additional restriction from its documentation. Or ask a new question about it.
I am trying to retrieve data from a user class webpages_membership for verifying a token password change.
Wehn I try to run this query to get the necessary information from the database:
bool any = ttf.webpages_Membership
.Any(x => x.UserId.Equals(userid)
&& x.PasswordVerificationToken == rt
&& x.PasswordVerificationTokenExpirationDate < DateTime.Now);
if (any == true) {
}
I get this exception
Unable to create a constant value of type 'DBContext.Models.Customers'. Only primitive types or enumeration types are supported in this context.
How can I avoid that exception?
Use this, to ensure that the LINQ expression only have constant values. Do also use == instead of .Equals (I'm not sure if .Equals can be correctly processed by LINQ. Perhaps it's possible, but I'm sure that == works fine).
var now = DateTime.Now;
ttf.webpages_Membership
.Any(x => x.UserId == userid &&
x.PasswordVerificationToken == rt &&
x.PasswordVerificationTokenExpirationDate < now);
LINQ examines the expression tree of the lambda predicate, and can transfer constant values to the server. I think it doesn't treat DateTime.Now as a constant, unless you capture it in a variable as shown.
I have a Where clause predicate which is fetching records .Now if I use the same in a where clause as a Predicate(ie Func(x,bool) ) it returns no records.My impression was that both were equivalent. - see below
var nonPredicate=this.ObjectSet.Where(x=>!String.IsNullOrEmpty(x.Email) && x.Email.Contains("AND")).ToList();
Func<Model,bool) clause=x=> x=>!String.IsNullOrEmpty(x.Email) && x.Email.Contains("AND");
var predicateRes=this.ObjectSet.Where(clause).ToList();
I expected same results in both cases -but the first produces 29 record result and the second 0 records.
Any Help would be great
Thanks
Linq to Entitites uses Expression<Func<?,?>> for it's query methods. Lambda expressions are automatically coersed to an expression (Expression<Func<?,?>>) or delegate (Func<?,?>) depending on the type of the variable or argument it is stored in.
// Inline expression
var nonPredicate = this.ObjectSet.Where(x =>
!string.IsNullOrEmpty(x.Email) && x.Email.Contains("AND")).ToList();
// Delegate type
Func<Model,bool> clauseDelegate = x =>
!string.IsNullOrEmpty(x.Email) && x.Email.Contains("AND");
// Expression type
Expression<Func<Model,bool>> clauseExpr = x =>
!string.IsNullOrEmpty(x.Email) && x.Email.Contains("AND");
var predicateRes = this.ObjectSet.Where(clauseExpr).ToList();
Expressions are an object representation of the lambda, which allows the library to translate it into SQL for communication with the database. The same is not possible with delegates, since the structure is already compiled into IL or machine code.
Is it possible within Linq in C#, to convert a string field in a database, to a long type - and use it in the query?
Here, tme is a unix time (long) - but the field in the database, targetdate - is a string.
I've tried:
var qbt = db.Calls
.Where(x => x.team == id && long.Parse(x.targetdate) <= tme);
However I get the message: LINQ to Entities does not recognize the method 'Int64 Parse(System.String)' method, and this method cannot be translated into a store expression.
I know you can convert before the linq query, but is there any way of using it WITHIN the linq query?
Thanks for any help,
Mark
try
var qbt = db.Calls.ToList()
.Where(x => x.team == id && long.Parse(x.targetdate) <= tme);
if you have many records you can limit them by team first and then call ToList like below
var qbt = db.Calls.Where(x => x.team == id).ToList()
.Where(i=>long.Parse(i.targetdate) <= tme);
Or You can use AsEnumerable
var qbt = db.Calls.AsEnumerable()
.Where(x => x.team == id && long.Parse(x.targetdate) <= tme);
This is to do with the way the Linq is translated into the backing query language, it might be easier to do a string comparison in this case, using tme.ToString(). If you pull the full collection down first, you could query like this but that means what it says: pulling down the full unfiltered (or at least less filtered) set.
You have to either change the database table to not store a string (you could create a computed column that converts it to a long or create a view if you cannot modify the existing table) or compare the value as string. The reason is that Entity Framework LINQ provider does not understand long.Parse and there is no method in SqlFunctions class for this purpose.
var stringTme = tme.ToString(CultureInfo.InvariantCulture);
var qbt = db.Calls
.Where(x => x.team == id && ((x.targetdate.Length < stringTme.Length)
|| (x.targetdate.Length == stringTme.Length && x.targetdate <= stringTme)));
You have to either change the database table to not store a string or compare the value as string. The reason is that Entity Framework LINQ provider does not understand long.Parse and there is no method in SqlFunctions class for this purpose.please use long.Parse()
This is not another question about 'How Can I Sort Dynamically (based on an arbitrary user provided field)?'
The question is -- how can I change sort order when I know the potential sorts in advance? (And thus avoid reflection / custom Expression building typically associated with truly dynamic sorting.)
Take for instance this subquery (shortened for this example) of a larger query:
(from solutionIds in context.csExtendedQAIncident_Docs
where solutionIds.tiRecordStatus == 1
&& (from solutionProductAssocation in context.csProductDocs
where solutionProductAssocation.iSiteId == Settings.Current.WebUtility().Onyx.SiteId
&& (from allowedProduct in context.KB_User_Allowed_Products
where allowedProduct.UserId == userId
select allowedProduct.ModelCode
).Contains(solutionProductAssocation.chModelCd)
select solutionProductAssocation.chIdNo).Distinct().Contains(solutionIds.chIdNo)
).OrderByDescending(s => s.dtUpdateDate)
.Select(s => s.chIdNo)
.Take(count ?? Settings.Current.WCFServices().Output.HomePage.MaxRows)
The OrderByDescending portion works as I would expect.
Now -- I want to factor that out like the following:
Expression<Func<csExtendedQAIncident_Doc, IComparable>> ordering = (s) => s.dtUpdateDate;
if (viewType == HomepageViewType.MostViewed)
ordering = (s) => s.vchUserField8;
else if (viewType == HomepageViewType.MostEffective)
ordering = (s) => s.vchUserField4;
and then use:
OrderByDescending(ordering)
This does compile, but blows up at run-time.
Unsupported overload used for query operator 'OrderByDescending'.
This of course comes from deep in the bowels of System.Data.Linq.SqlClient.QueryConverter -- in particular VisitSequenceOperatorCall. Reflectoring that code reveals that the following conditions must be met for OrderByDescending to properly evaluate. 'mc' is the MethodCallExpression passed into the method.
if (((mc.Arguments.Count != 2) || !this.IsLambda(mc.Arguments[1]))
|| (this.GetLambda(mc.Arguments[1]).Parameters.Count != 1))
{
break;
}
So essentially that MethodCallExpression has to have 2 arguments, the second of which has to be a Expressions.LambdaExpression with a single parameter (presumably the sort field). If that code breaks out, the exception that I got is thrown.
So clearly I have not constructed the expression correctly. Without digging in any further here, does anyone know how to correctly construct the sorting Expression?
I think the unsupported part of your code is the use of IComparable as a general return type for your ordering expression. If you consider the plain use of OrderByDescending, the compiler-generated lambda expression has a return type of the type of the property that you're ordering by: for example, an Expression<Func<csExtendedQAIncident_doc, string>> for a string property.
One possible answer, although I'm not sure whether it works in your case, is to first create an unordered query:
IQueryable<Foo> unorderedQuery = from f in db.Foo select f;
And then, depending on the sort:
IOrderedQueryable<Foo> orderedQuery = unorderedQuery
.OrderBy(f => f.DefaultSortKey);
if (sortBy == SortByName)
orderedQuery = unorderedQuery.OrderBy(f => f.Name);
else if (sortBy == SortByDate)
orderedQuery = unorderedQuery.OrderBy(f => f.Date);
// etc.
I believe that this will not work unless the two possible fields have the identical type.
Then the linq to sql will (if possible) correctly create the relevant sql.
so for example if both of those fields were DateTimes:
Expression<Func<csExtendedQAIncident_Doc, DateTime>> ordering =
s => s.dtUpdateDate;
if (viewType == HomepageViewType.MostViewed)
ordering = (s) => s.vchUserField8; // a DateTime
else if (viewType == HomepageViewType.MostEffective)
ordering = (s) => s.vchUserField4; // another DateTime
Then this would work just fine (I tested it and it worked)
You could instead do a per type order by either a series of nested switch/if statements of by constructing a dictionary or similar structure to get them.
For the linq to sql to work without explicit dynamic creation of the query I believe it must know the precise type of the query as opposed to just it being an IComparable...