linq orderby query inside of an if statement - c#

I'm trying to do some code which basically says do search, if orderByLastName is true order by lastname and if false order by first name.
if(orderByLastName)
{
var query = from p in db.People
orderby p.LastName
select new {Name = p.FirstName + " " + p.LastName}
}
else
{
var query = from p in db.People
orderby p.FirstName
select new {Name = p.FirstName + " " + p.LastName}
}
The above code is my attempt at accomplishing this. It doesn't work because query does not exist outside of the if context which is clearly bad! And also I'm pretty sure the code violates the dry principle. Can someone see a nicer way of doing this? Thanks.

You can run as many queries on your IQueryable collection as you want, all of them will be executed right in place where you will make first cast of conversion to IEnumerable.
var query = db.People;
if(orderByLastName)
{
query = query.OrderBy(t=>t.LastName)
}
else
{
query = query.OrderBy(t=>t.FirstName)
}
var result = query.Select(t=> new {Name = t.FirstName + " " + t.LastName});

This is another solution :
Func<PeopleType, string> orderby;
if(orderByLastName)
orderby = t => t.LastName;
else
orderby = t => t.FirstName;
var result = db.People.OrderBy(orderby).Select(t => new { Name = t.FirstName + " " + t.LastName });

Related

LinQ query - Cannot use Date as its non-primitive EDM type. Also cannot convert DateTime to String

I have below linQ Query for which I am getting the error:
LINQ to Entities does not recognize the method 'System.String ToString(System.DateTime)' method, and this method cannot be translated into a store expression.
var query = from i in Expenditure
join d in Department on i.DepartId equals d.dID
where i.Status == "Audit"
group i by new { i.InvoiceId, d.Title, i.InvoiceDate } into g
select new
{
id = g.Key.InvoiceId,
txt = g.Key.Title + " // " + g.Key.InvoiceId + " // " + Convert.ToString(g.Key.InvoiceDate)
};
I want txt output as follow:
Health // Inv001 // 12-03-2018
Education // Inv002 // 23-03-3018
Problem is with InvoiceDate (Datetime) field for which I initially wrote (without the Convert)as: g.Key.InvoiceDate
but I got error as: Unable to cast the type 'System.DateTime' to type 'System.Object'. LINQ to Entities only supports casting EDM primitive or enumeration types.
Can anyone suggest an easy solution? Thanks.
ToString isn't an SQL function, therefore it can't be done within the SQL query.
Try this:
var query = (from i in Expenditure
join d in Department on i.DepartId equals d.dID
where i.Status == "Audit"
group i by new { i.InvoiceId, d.Title, i.InvoiceDate } into g
select new
{
g.Key.InvoiceId,
g.Key.Title,
g.Key.InvoiceDate,
}).ToList()
.select new
{
id = InvoiceId,
txt = Title + " // " + InvoiceId + " // " + Convert.ToString(InvoiceDate)
};
Everything after the .ToList() will be done in memory, where you can use any .NET method.
Instead of assembling txt in database and force Linq To Entities to transform your logic into SQL, first retrieve the data and then apply transformations
Try following
var query =
(from i in Expenditure
join d in Department on i.DepartId equals d.dID
where i.Status == "Audit"
group i by new { i.InvoiceId, d.Title, i.InvoiceDate } into g
select new
{
id = g.Key.InvoiceId,
title = g.Key.Title,
invoiceId = g.Key.InvoiceId,
invoiceDate = g.Key.InvoiceDate
})
.ToList()
.Select(it => new
{
id = it.id,
txt = it.title + " // " + it.invoiceId + " // " + it.invoiceDate
});

One context reference LINQ query throws multiple references exception - BUG?

I'm using the following code:
using(MainEntities mainContext = new MainEntities())
{
return (from member in mainContext.aspnet_Membership
where adminGroupUserIDs.Contains(member.UserId)
select new
{
FullName = member.FirstName + " " + member.LastName,
UserName = (from user in mainContext.aspnet_Users
where user.UserId == member.UserId
select user.UserName)
}).ToList();
}
where adminGroupUserIDs is an IQueryable<GUID> that is formed from a query to a different instance of MainEntities.
With this query LINQ complains that:
The specified LINQ expression contains references to queries that are associated with different contexts.
Any ideas why?
I can't be certain from the code you show here, but I'm pretty sure that adminGroupUserIDs is the result of another query that hasn't been retrieved yet, and was created with a different instance of MainEntities. You can't mix queries from different contexts, not even different instances of the same context class. Try changing it to the following:
var loadedAdminGroupUserIDs = adminGroupUserID.ToArray();
using(MainEntities mainContext = new MainEntities())
{
return (from member in mainContext.aspnet_Membership
where loadedAdminGroupUserIDs.Contains(member.UserId)
select new
{
FullName = member.FirstName + " " + member.LastName,
UserName = (from user in mainContext.aspnet_Users
where user.UserId == member.UserId
select user.UserName)
}).ToList();
}
Try adding .FirstOrDefault() to your subquery.
using(MainEntities mainContext = new MainEntities())
{
return (from member in mainContext.aspnet_Membership
where adminGroupUserIDs.Contains(member.UserId)
select new
{
FullName = member.FirstName + " " + member.LastName,
UserName = (from user in mainContext.aspnet_Users
where user.UserId == member.UserId
select user.UserName).FirstOrDefault()
}).ToList();
}

how to sort an anonymous type without named columns

Building from this question: Trying to concatenate columns in LINQ
Now I want to sort:
var orderByIndexVal = Convert.ToInt32(Request["iSortCol_0"]);
var direction = Request["sSortDir_0"];
var gridInfo =
from leader in db.SchoolLdrAdminAccesses
join emp in db.Employees
on leader.ID equals emp.ID
select new List<string> { leader.ID, emp.FirstName + " " + emp.LastName };
return Json(new
{
sEcho = param.sEcho,
iTotalRecords = gridInfo.Count(),
iTotalDisplayRecords = gridInfo.Count(),
aaData = gridInfo.ToArray()
},
JsonRequestBehavior.AllowGet);
After reading this post:
LINQ sorting anonymous types?
My issue is that I don't have anything named in my gridInfo
What I've tried so far:
if (direction == "asc")
{
gridInfo = gridInfo.OrderBy(gi => gi[orderByIndexVal]);
}
else
{
gridInfo = gridInfo.OrderByDescending(gi => gi[orderByIndexVal]);
}
But I'm getting the following error:
LINQ to Entities does not recognize the method 'System.String
get_Item(Int32)' method, and this method cannot be translated into a
store expression.
On the following block of code:
return Json(new
{
sEcho = param.sEcho,
iTotalRecords = gridInfo.Count(),
iTotalDisplayRecords = gridInfo.Count(),
aaData = gridInfo.ToArray()
},
JsonRequestBehavior.AllowGet);
You need to materialize the list, so the order by doesn't happen in the DB, but in .NET, after the concatenation takes place.
var gridInfo = (from leader in db.SchoolLdrAdminAccesses
join emp in db.Employees
on leader.ID equals emp.ID
select new string[]{ leader.ID.ToString(),
emp.FirstName + " " + emp.LastName })
.ToList();
Also note that using an array instead of a list uses less memory. Hope that helps.
I think this is the problem
new List<string> { leader.ID, emp.FirstName + " " + emp.LastName };
the anonymous type you are selecting is two columns { Int, String } not a simple List
Just Select new { leader.ID, emp.FirstName + " " + emp.LastName }; the Select statement will make it an IEnumerable automatically, so you don;t need the List<> part
I am assuming leader.ID is an Int here (which may be wrong)

Perform group and join using LINQ

Does anyone have any suggestions about how I might do this using just LINQ?
var statements = db.vwOutstandingStatements.ToList();
var amounts = (from s in db.vwOutstandingStatements
group s by s.Id into v
select new
{
Id = v.Key,
amount = v.Sum(a => a.Amount)
}).ToList();
List<vmVendorStatements> statementsToProcess = new List<vmVendorStatements>();
foreach (var amount in amounts)
{
var statement = statements.Find(s => s.Id == amount.Id);
statementsToProcess.Add(new vmVendorStatements()
{
Id = statement.Id,
PropertyAddress = statement.PropertyNumber + " " + statement.PropertyStreet + " " + statement.PropertyTown,
StatementDate = statement.StatementDate.ToLongDateString(),
Amount = amount.amount.ToString()
});
}
Statements is from a sql view via EF5. I run the LINQ to get the data grouped by the sum of the amounts in the returned view and then join it back to show some of the detail from the returned view along with the sums amounts. StatementsToView is my view model to get the data into an MVC view.
I'm sure it could be done in SQL, and I might do that in any case, but there also seems as though there must be a neater solution to the above too.
Thanks,
Jason.
You can just grab out the first item in the group rather than re-querying just to find the first item:
var statementsToProcess =
(from s in db.vwOutstandingStatements
group s by s.Id into v
let first = v.First()
select new vmVendorStatements()
{
Id = v.Key,
amount = v.Sum(a => a.Amount),
PropertyAddress = first.PropertyNumber + " " + first.PropertyStreet + " " + first.PropertyTown,
StatementDate = first.StatementDate.ToLongDateString(),
}).ToList();

return one string with multiple column value linq

I have a query.
Is it possible to return One string with multiple column value in linq ??
Like this
string ProductName = ((from P in DataModel.DIS_PRODUCT
join M in DataModel.SET_PACK_UNIT on P.PUNIT_ID equals M.ID
where P.PRODUCT_ID == ProdictId
select P.PRODUCT_NAME +" " + P.WEIGHT + " "+ M.UNIT_SYMBLE)
.Take(1)
).ToString();
You're using Take(1) which means you're still getting an IEnumerable<string> or an IQueryable<string>. Just use First() (or possibly FirstOrDefault()) instead of Take(1) and you can drop the ToString() call as well.
string productName = (from P in DataModel.DIS_PRODUCT
join M in DataModel.SET_PACK_UNIT
on P.PUNIT_ID equals M.ID
where P.PRODUCT_ID == ProdictId
select P.PRODUCT_NAME + " " + P.WEIGHT + " "+ M.UNIT_SYMBLE)
.FirstOrDefault();
That will only work if your LINQ provider supports the string concatenation operation. An alternative is to fetch just the columns you want, and then concatenate at the caller:
var query = from P in DataModel.DIS_PRODUCT
join M in DataModel.SET_PACK_UNIT
on P.PUNIT_ID equals M.ID
where P.PRODUCT_ID == ProdictId
select new { P.PRODUCT_NAME, P.WEIGHT, M.UNIT_SYMBLE };
var result = query.FirstOrDefault();
if (result != null)
{
string productName = result.PRODUCT_NAME + " " +
result.WEIGHT + " " +
result.UNIT_SYMBLE;
// Use the name
}
else
{
// No results
}
Another more clear way is the following
var ProductsQueryItem = (from p in Products
select new
{
Name = e.ProductName+ " " + e.weight +e.UNIT_SYMBLE
})
.FirstOrDefault();
Now you can use it directly with ProductsQueryItem .Name

Categories