Problem with order by in LINQ - c#

I'm passing from the controller an array generated by the next code:
public ActionResult GetClasses(bool ajax, string kingdom)
{
int _kingdom = _taxon.getKingdom(kingdom);
var query = (from c in vwAnimalsTaxon.All()
orderby c.ClaName
select new { taxRecID = c.ClaRecID, taxName = c.ClaName }).Distinct();
return Json(query, JsonRequestBehavior.AllowGet);
}
The query List should be ordered, but it doesn't work, I get the names of the classes ordered wrong in the array, because I've seen it debugging that the names are not ordered.The view is just a dropdownbox loaded automatically, so I'm almost sure the problem is with the action. Do you see anything wrong?Am I missing something?

I think gmcalab is almost there. The reason it's not working is that Distinct blows away the ordering. So you need Distinct THEN OrderBy. But this means you have to sort by the new attribute name:
var query = (from c in vwAnimalsTaxon.All()
select new { taxRecID = c.ClaRecID, taxName = c.ClaName }
).Distinct().OrderBy(t => t.taxName);

Give this a try:
var query = (from c in vwAnimalsTaxon.All()
select new { taxRecID = c.ClaRecID, taxName = c.ClaName }
).Distinct().OrdeyBy(c => c.ClaName);

In LINQ the Distinct method makes no guarantees about the order of results. In many cases the Distinct causes the OrderBy method to get optimized away. So it's necessary to do the OrderBy last, after the Distinct.
var query = (from c in vwAnimalsTaxon.All()
select new { taxRecID = c.ClaRecID, taxName = c.ClaName })
.Distinct()
.OrderBy(c => c.ClaName);

The select will also blow away the sorting. So either Distinct or Select needs orderby after.

Related

IQueryable vs ICollection (List)

I have such a case study:
ToList() case:
List<CategoryType> categories = (from c in categoryTypes where c.IsSysParam == isSysParamCategory select new CategoryType { Code = c.Code, CreateDate = c.CreateDate, EditDate = c.EditDate, IsProductCategory = c.IsProductCategory, IsSysParam = c.IsSysParam, Name = c.Name, TypeId = c.TypeId, ValueTypes = new List<ValueType>() }).ToList();
List<ValueType> valueTypeList = new List<ValueType>();
foreach (var c in categories.ToList())
{
valueTypeList = categoryTypes.Where(x => x.TypeId == c.TypeId).SelectMany(v => v.ValueTypes).Where(v => v.ParentValueId == null).ToList();
c.ValueTypes = valueTypeList;
}
IQueryable case:
When I change in first query - List<CategoryType> to IQueryable<CategoryType> and remove ToList() from the end of query then I dont have any result:
Question:
I am asking for an explanation, I do not understand why this is happening. I know that the IQueryable makes some part of the work on the database side.
Edit:
The code is working, pictures shows the final effect.
I have:
public IQueryable<CategoryType> CategoryTypePagination { get; set; }
and in the end of ToList() case:
this.CategoryTypePagination = categories.AsQueryable();
in IQueryable case just removed .AsQueryable()
You have to look at "Deferred Query Execution" and "Immediate Query Execution"
Accrodingly to this, IQueryable uses something called lazy loading.
So the results of IQueryable aren't loaded until they are first used, for example in Sum, ToList or ToArray methods, while ToList requieres data to be loaded. Thus you see the difference after initailizing both objects.

Returning List<string> from Linq query returns query syntax not values

I have the below code to return a list of strings.
public List<string> Top5CodesForToday()
{
var date = DateTime.Now;
var resultList = new List<string>();
using (var db = new PillowContext())
{
var qry = (from d in db.DownTimes
where DbFunctions.TruncateTime(d.DateTime) == DbFunctions.TruncateTime(date)
group d by new {d.Code}
into g
let total = g.Sum(x => x.Amount)
orderby total descending
let top5 = g.Take(5).ToList()
select new {g.Key.Code, Total = total});
foreach (var item in qry)
{
int x = item.Code;
var results = from r in db.DownTimeCodes
where r.Code == x
select r.Description;
resultList.Add(results.ToString());
}
}
return resultList;
}
When I look at the contents of returnList I am seeing the correct number of items however each item is made up of the actual query syntax, not the data itself. I have seen this before and usually solve it by doing .ToList() however I am unsure how I could change my code to solve this
The problem here is that when you are calling ToString the query is not executed yet, so essentially you are calling ToString on a IQueryable object, receiving the query instead of results. You need to call something to execute the query.
You can call ToList() still:
var results = (from r in db.DownTimeCodes
where r.Code == x
select r.Description).ToList();
resultList.AddRange(results);
Or, if you expect just one result, call FirstOrDefault()/SingleOrDefault():
var results = (from r in db.DownTimeCodes
where r.Code == x
select r.Description).FirstOrDefault();
resultList.Add(results);
You are calling ToString() on List<>. As default for most complex types, it just writes out type name not the data.
This line
resultList.Add(results.ToString());
should be changed to
resultList.AddRange(results);

List of two attributes in same class

I have an Entity Class called Session and it containts two attributes: LecturerOne and LectureTwo. I want to create a union of all the distinct names in LecturerOne and LecturerTwo:
I got just LecturerOne working.
public List<string> ListLecturer()
{
var lecturerNames = (from s in db.Sessions
select s.LecturerOne).Distinct();
List<string> lecturerList = lecturerNames.ToList();
return lecturerList;
}
One option:
var list = db.Sessions.SelectMany(s => new string[] { s.LecturerOne,
s.LecturerTwo })
.Distinct()
.ToList();
I don't know offhand how EF will treat that, but it's worth a try...
Alternatively, similar to Jamiec's answer but IMO simpler:
var list = db.Sessions.Select(s => s.LecturerOne)
.Union(db.Sessions.Select(s => s.LecturerTwo))
.ToList();
(Union already returns distinct results, so there's no need to do it explicitly.)
var lecturerOnes = (from s in db.Sessions
select s.LecturerOne);
var lecturerTwos = (from s in db.Sessions
select s.LecturerTwo);
List<string> lecturerList = lecturerOnes.Union(lectureTwos).ToList();

Help troubleshooting LINQ query

I have this LINQ query:
var returnList = from TblItemEntity item in itemList
join TblClientEntity client in clientList
on item.ClientNo equals client.ClientNumber
join TblJobEntity job in jobList
on item.JobNo equals job.JobNo
where item.ClientNo == txtSearchBox.Text //Is this filter wrong?
orderby client.CompanyName
select new { FileId = item.FileId, CompanyName = client.CompanyName, LoanStatus = item.LoanStatus, JobNo = job.JobNo, JobFinancialYE = job.JobFinancialYE, VolumeNo = item.VolumeNo };
Why doesn't this return anything?
P/S : All of them are of string datatype.
Have you tried to remove parts of the join to figure out where the problem is and then add those removed parts back again one after one? Start with:
var returnList = from TblItemEntity item in itemList
where item.ClientNo == txtSearchBox.Text //Is this filter wrong?
select new { FileId = item.FileId };
Since you're doing inner joins there could be that one of the joins filters out all the items.
EDIT: When debugging don't expand the return type, the select new {FileId = item.FileId} is all you need to debug.
Still waiting on that sample data.
You say you're getting results filtering by other attributes so why should this be any different? Assuming the user-input txtSearchBox has a reasonable value, try printing the values out onto the debug console and see if you're getting reasonable results. Look at the output window. Try this version of your query:
Func<string,bool> equalsSearch = s =>
{
var res = s == txtSearchBox.Text;
Debug.WriteLine("\"{0}\" == \"{1}\" ({2})", s, txtSearchBox.Text, res);
return res;
};
var returnList = from TblItemEntity item in itemList
join TblClientEntity client in clientList
on item.ClientNo equals client.ClientNumber
join TblJobEntity job in jobList
on item.JobNo equals job.JobNo
//where item.ClientNo == txtSearchBox.Text //Is this filter wrong?
where equalsSearch(item.ClientNo) //use our debug filter
orderby client.CompanyName
select new { FileId = item.FileId, CompanyName = client.CompanyName, LoanStatus = item.LoanStatus, JobNo = job.JobNo, JobFinancialYE = job.JobFinancialYE, VolumeNo = item.VolumeNo };
Why doesn't this return anything?
There two possibilites:
1) The join is empty, that is, no items, clients and jobs have matching ID's.
2) The where clause is false for all records in the join.
To troubleshoot this you will have to remove the where clause and/or some of the joined tables to see what it takes to get any results.

How should I write this Linq to Entity query?

I'm new to Linq to Entity stuff, so I don't know if what I'm doing is the best approach.
When I do a query like this it compiles, but throws an error that it doesn't recognize the method GetItemSummaries. Looking it up, this seems to be because it doesn't like a custom method inside the query.
return (from c in _entity.Category
from i in c.Items
orderby c.Id, i.Id descending
select new CategoryDto
{
Id = c.Id,
Name = c.Name,
Items = GetItemSummaries(c)
}).ToList();
private IEnumerable<ItemSummary> GetItemSummaries(CategoryDto c)
{
return (from i in c.Items
select new ItemSummary
{
// Assignment stuff
}).ToList();
}
How would I combine this into a single query since I can't call a custom method?
I tried just replacing the method call with the actual query, but then that complains that ItemSummary isn't recognized instead of complaining that the method name isn't recognized. Is there any way to do this? (Or a better way?)
You should be able to do the following:
return (
from c in _entity.Category
orderby c.Id descending
select new CategoryDto
{
Id = c.Id,
Name = c.Name,
Items = (
from i in c.Items
order by i.Id descending
select new ItemSummary
{
// Assignment stuff
}
)
}).ToList();
It's just a matter of making sure that ItemSummary is public so that it's visible to the query.
If it's just a Dto though, you could use an anon type, eg:
from i in c.Items
order by i.Id descending
select new
{
Id = i.Id,
Name = i.Name
}
This creates a type with the 'Id' and 'Name' properties. All depends what your consuming code needs :)
Try making the GetItemSummaries method an extension method on the Category class
private static IEnumerable<ItemSummary> GetItemSummaries(this Category c)
and then call it with
select new Category
{
Id = c.Id,
Name = c.Name,
Items = c.GetItemSummaries()
}).ToList();
Marc

Categories