I'm using L2S for database operations in my asp.net mvc application I have following simple query in my repository
(from pt in db.oaProjectTasks
where pt.ProjectID == ProjectID
join t in db.oaTasks on pt.TaskID equals t.TaskID
where t.ParentTaskID == null
let daypassed = GetDaysPassed(t.StartDate,t.Duration)
select new ChartTask{TaskNumber = t.TaskNumber,StartDate = t.StartDate,
DurationRemaining = t.Duration - daypassed,TaskDescription = t.Task, DaysPassed = daypassed,Duration = t.Duration }).ToList();
below is the defination of GetDayPassed method
private int GetDaysPassed(DateTime StartDate, int Duration)
{
int retVal;
if ((DateTime.Now - StartDate).Days > 0)
{
if ((DateTime.Now - StartDate.AddDays(Duration)).Days > 0)
{
retVal = Duration;
}
else
{
retVal = (DateTime.Now - StartDate).Days;
}
}
else
{
retVal = 0;
}
return retVal;
}
there is no compile time error, however, when i execute the code it gives me invalidOperationException with following message.
Could not translate expression 'Table(oaProjectTask).Where(pt => (pt.ProjectID == Invoke(value(System.Func`1[System.Int64])))).Join(Table(oaTask), pt => pt.TaskID, t => t.TaskID, (pt, t) => new <>f__AnonymousType5f`2(pt = pt, t = t)).Where(<>h__TransparentIdentifier2 => (<>h__TransparentIdentifier2.t.ParentTaskID == null)).Select(<>h__TransparentIdentifier2 => new
how can I get around this? if calling a method in query is not allowed how can I make a simple calculation in Linq query instead of calling GetDayPassed method?
You can try this:
(from pt in db.oaProjectTasks
where pt.ProjectID == ProjectID
join t in db.oaTasks on pt.TaskID equals t.TaskID
where t.ParentTaskID == null
select t)
.ToList() // T-SQL query will be executed here and result will be returned
.Select(t => new ChartTask {
TaskNumber = t.TaskNumber,
StartDate = t.StartDate,
DurationRemaining = t.Duration - GetDaysPassed(t.StartDate,t.Duration),
TaskDescription = t.Task,
DaysPassed = GetDaysPassed(t.StartDate,t.Duration),
Duration = t.Duration });
The problem is that Linq to Sql tries to translate your custom function to T-SQL and since it doesn't know how to do that it will throw the exception. In my case Linq will construct the query, execute it (after the call to .ToList()) and your function will be called as Linq to objects query.
Related
I have the following linq query that is throwing an error if a budget doesn't have any categories. Am I doing something wrong? Can I just set sum to return 0 if there are no categories? I'm fairly new to linq to sql.
var r = from rec in DbContext.budgets
where rec.budgetID == updatedBudget.budgetID
select new
{
rec.budgetID,
rec.totalIncome,
totalSpent = rec.categories.Sum(a => a.amount)
};
return new JsonResult(r.FirstOrDefault(), JsonSettings);
you can try this.
var r = from rec in DbContext.budgets
where rec.budgetID == updatedBudget.budgetID
select new
{
rec.budgetID,
rec.totalIncome,
totalSpent = rec.categories != null ? rec.categories.Sum(a => a.amount) : 0
};
return new JsonResult(r.FirstOrDefault(), JsonSettings);
Have read other responses to similar issuebut I can not use PredicateBuilder, or copy its source. I'm trying what I've read here:
<https://blogs.msdn.microsoft.com/meek/2008/05/02/linq-to-entities-combining-predicates/
but as I'm newb, am having trouble with translating what I'm reading to what I'm applying. I have created a L2E query, and trying to append a series of OR clauses onto the WHERE:
So as simplified snippet (this one will be AND'd with the previously already defined WHERE clause):
if (firstParm == "realtor")
query = query.Where(x=> x.A == "realtor");
Now trying to OR:
if (secondParm == "clown")
// how to add this one as an OR to the above query:
query = query.OR(x=> x.fool == "clown");
I understand this can be done also with Union, but not clear on the syntax:
query = query.Union(x=> x.fool == "clown"); // ??
I've also referenced:
Combining two expressions (Expression<Func<T, bool>>)
Unable to create a compound Expression<Func<string, bool>> from a set of expressions
but again, I am new to LINQ and especially Expression Trees, so need more fillin.
There are two ways to generate expressions.
Use the compiler to do it.
Expression<Func<Person, bool>> = p => p.LastName.Contains("A");
Limitations: The only expressions that can be generated this way are instances of LambdaExpression. Also, it is rather complicated to extract parts of the expression and combine with other parts.
Use the static methods at System.Linq.Expressions.Expression.
In order to generate dynamic expressions, you can either choose between different compiler-generated expressions:
// using Record and Records as a placeholder for the actual record type and DbSet property
Expression<Func<Record,bool>> expr;
if (firstParam == "realtor") {
if (secondParam == "clown") {
expr = x => x.A == "realtor" || x.fool == "clown";
} else {
expr = x => x.A == "realtor";
}
} else {
if (secondParam == "clown") {
expr = x => x.fool="clown";
} else {
expr = x => false;
}
}
var ctx = new MyDbContext();
var qry = ctx.Records.Where(expr).Select(x => new {x.A, x.fool});
Or, you can dynamically create the expression using the static methods:
(Add using System.Linq.Expressions; and using static System.Linq.Expressions.Expression; to the top of the file.)
Expression expr;
var parameter = Parameter(typeof(Record));
if (firstParam == "realtor") {
expr = Equals(
MakeMemberAccess(parameter, typeof(Record).GetProperty("A")),
Constant("realtor")
);
}
if (secondParam == "clown") {
var exprClown = Equals(
MakeMemberAccess(parameter, typeof(Record).GetProperty("fool")),
Constant("clown")
);
if (expr == null) {
expr = exprClown;
} else {
expr = Or(expr, exprClown);
}
}
var lambda = Lambda<Func<Record,bool>>(expr, new [] {parameter});
var ctx = new MyDbContext();
var qry = ctx.Records.Where(lambda).Select(x => new {x.A, x.fool});
Given a query with a type unknown at compile time, so any variable referring to it must be IQueryable only, and not IQueryable<T>:
IQueryable qry = ctx.GetQuery(); //dynamically built query here
var parameter = Parameter(qry.ElementType);
if (firstParam == "realtor") {
expr = Equals(
MakeMemberAccess(parameter, qry.ElementType.GetProperty("A")),
Constant("realtor")
);
}
if (secondParam == "clown") {
var exprClown = Equals(
MakeMemberAccess(parameter, qry.ElementType.GetProperty("fool")),
Constant("clown")
);
if (expr == null) {
expr = exprClown;
} else {
expr = Or(expr, exprClown);
}
}
var lambda = Lambda(expr, new [] {parameter});
//Since we don't have access to the TSource type to be used by the Where method, we have
//to invoke Where using reflection.
//There are two overloads of Queryable.Where; we need the one where the generic argument
//is Expression<Func<TSource,bool>>, not Expression<Func<TSource,int,bool>>
var miWhere = typeof(Queryable).GetMethods().Single(mi => {
mi.Name == "Where" &&
mi.GetParameters()[1].ParameterType.GetGenericArguments()[0].GetGenericArguments().Length == 2
});
qry = miWhere.Invoke(null, new [] {qry, lambda});
For Or you can try
if (secondParm == "clown")
{
query = query.Where(x=> x.fool == "clown" || x.fool==x.fool);
}
OR
if (secondParm == "clown")
{
query = query.Where(x=> x.fool == "clown" || true );
}
I have a linq query which joins a couple of tables and returns the value into an object. The query was working fine, till i added a where clause to in. Aftre the where clause, my query returns null.
Here's the code:
List<Int32> resourceSupervisorIdList = new List<Int32>();
resourceSupervisorIdList.Add(searchCriteriaTimesheet.ResourceId);
foreach (resource res in allSubordinateResources)
{
if (!resourceSupervisorIdList.Contains(res.id_resource))
resourceSupervisorIdList.Add(res.id_resource);
}
using (tapEntities te = new tapEntities())
{
var timesheetAll = (from tsh in te.timesheet_header
join rs in te.resources on tsh.id_resource equals rs.id_resource
join tsd in te.timesheet_detail on tsh.id_timesheet equals tsd.id_timesheet
where (resourceSupervisorIdList.Contains(rs.id_resource_supervisor))
select new TimesheetHeaderDetailsItem()
{
OrganizationId = rs.id_organization,
ProjectId = tsd.id_project,
StartDate = tsh.dte_period_start,
EndDate = tsh.dte_period_end,
ApprovedDate = tsh.dte_approved,
RejectedDate = tsh.dte_rejected,
SubmittedDate = tsh.dte_submitted,
});
if (timesheetAll == null || timesheetAll.Count() == 0)
{
return result;
}
}
Now, after adding the where clause, the code runs into the if condition. There are matching records in the table, but still i'm not able to get any records.
rs.id_resource_supervisor
is of type int in the mysql db.
public static IQueryable<SearchProfile> FilterData(string Filter, Repository<SearchProfileContext> dc)
{
IQueryable<SearchProfile> data = null;
var predicate = PredicateBuilder.True<SearchProfile>();
Filter = ExcludedParam(Filter);
if (!string.IsNullOrEmpty(Filter))`enter code here`
{
var stringToSplit = Filter;`enter code here`
List<string[]> arrays = new List<string[]>();
var primeArray = stringToSplit.Split('|');
for (int i = 0; i < primeArray.Length; i++)
{
string first = primeArray[i];
if (first.Contains("chkOrientation") == true)
{
string[] Array = first.Replace("chkOrientation=", "").Split(',');
predicate = predicate.And(a => Array.Contains(a.OrientaionID.ToString()));
}
if (first.Contains("chkProfession") == true)
{
string[] Array = first.Replace("chkProfession=", "").Split(',');
**predicate = predicate.And(a => Array.Contains(SqlFunctions.StringConvert((Double)a.ProfessionID)));**
}
}
data = dc.Select<SearchProfile>().Where(predicate).Distinct();
return data;
}
data = (from a in dc.Select<SearchProfile>().Where(a => a.PersonID > 0) select a).Distinct();
return data;
}
When I ran my program, I got this nasty error below:
LINQ to Entities does not recognize the method Int32 ToInteger(System.Object) method, and this method cannot be translated into a store expression.
then,I used SqlFunctions.StringConvert to make it work but the SQL LINQ generated was not evaluating. This is the sample output (it is comparing '1' and '2' instead of 1 and 2)**
Why are you casting a.ProfessionID to double? What type is a.ProfessionID of?
I think there is implicit conversion to integer, which causes calling the ToInteger method.
And why don't you convert items in Array to integer in the first place, and then use Array of ints in the query?
I'm trying to implement a T-SQL equivalent of a where in (select ...) code in LINQ.
This is what I have now:
int contactID = GetContactID();
IEnumerable<string> threadList = (from s in pdc.Messages
where s.ContactID == contactID
group 1 by new { s.ThreadID } into d
select new { ThreadID = d.Key.ThreadID}).ToList<string>();
var result = from s in pdc.Messages
where threadList.Contains(s.ThreadID)
group new { s } by new { s.ThreadID } into d
let maxMsgID = d.Where(x => x.s.ContactID != contactID).Max(x => x.s.MessageID)
select new {
LastMessage = d.Where(x => x.s.MessageID == maxMsgID).SingleOrDefault().s
};
However, my code won't compile due to this error for the ToList():
cannot convert from
'System.Linq.IQueryable<AnonymousType#1>'
to
'System.Collections.Generic.IEnumerable<string>'
Anyone have any suggestions on how to implement this? Or any suggestions on how to simplify this code?
Your query returns a set of anonymous types; you cannot implicitly convert it to a List<string>.
Instead, you should select the string itself. You don't need any anonymous types.
Change it to
var threadList = pdc.Messages.Where(s => s.ContactID == contactID)
.Select(s => s.ThreadID)
.Distinct()
.ToList();
var result = from s in pdc.Messages
where threadList.Contains(s.ThreadID)
group s by s.ThreadID into d
let maxMsgID = d.Where(x => x.ContactID != contactID).Max(x => x.MessageID)
select new {
LastMessage = d.Where(x => x.MessageID == maxMsgID).SingleOrDefault()
};