Linq order by ascending sort by descending - c#

Sorry for title, but i didn't know how to write it better. I will try in post.
When I am trying to get values from database using linq with orderby something strange happens. Let's look on 4 queries:
//1
var badAsc = new ConcurrentBag<int>((from x in se.produkts orderby x.numerProduktu select x.numerProduktu));
//2
var bagDesc = new ConcurrentBag<int>((from x in se.produkts orderby x.numerProduktu descending select x.numerProduktu));
//3
var listAsc = (from x in se.produkts orderby x.numerProduktu select x.numerProduktu).ToList();
//4
var listdesc = (from x in se.produkts orderby x.numerProduktu descending select x.numerProduktu).ToList();
We got 2 ConcurrentBags<int> and 2 List<int>. What I was expecting from this is that 1 and 3 will be the same and also 2 and 4 will be the same. Check what values i got:
Ascending sort for ConcurrentBag<int> is in fact descending. On Microsoft site we can read, that ConcurrentBag is good when sorting does not matters, but as we can see in bagDesc, sorting is kept. To show, that I don't have any strange things in database I also make two List<int> where sorting is kept as it should be.
Executing select * from produkt in my database gives me values sorted like listAsc and bagDesc.
Database is mssql 2014 and numerProduktu is primary key in this table.
Do anybody know what happened there?

See here.
The ConcurrentBag appears to be implemented as a stack rather than a
queue. That is, the last item added is the first item removed. I
wouldn't count on that, though.
So they are getting added in reverse order. However, order is not meant to be reliably consistent in ConcurrentBag, so it's not guaranteed to always behave that way, especially if accessed by multiple threads.
If you care about maintaining the original order of entry, then you probably want a ConcurrentQueue.

Related

MVC Joining many 2 many tables and filling list based on result in c#

I am doing a school project and need help with this last problem I am having.
Currently I am trying to do a many 2 many join and then fill an IEnumerable list with the result - using linq and lambda.
The purpose is to show the compatible games along with every product.
My code as of now:
else
{
var result = (from g in db.Games
join gs in db.GameSize
on g.GameId equals gs.GameId
join s in db.Size
on gs.SizeId equals s.SizeId
join p in db.Product
on s.SizeId equals p.SizeId
select p.Size.Name);
games = db.Games
.Where(game => game.GameSize
.All(s => s.Size.Name == result.FirstOrDefault()));
}
My idea is to join through the tables and find the gameid who have a matching productid - and then add them to "games".
I am aware that this table design is horrible and that I am only getting the first result in the list with FirstOrDefault().
Does anyone have a suggestion or solution to help me? Thanks.
Please ask if I am not making any sense.
Essentially I just wan't to show the games linked to a size. My table looks like this:
--SIZE
insert into size values ('Large')
insert into size values ('Medium')
insert into size values ('Small')
--GAMES
insert into games values ('Magic The Gathering')
insert into games values ('Pokemon')
insert into games values ('Dead of Winter')
--GAMESIZE (RELATION GAMES AND SIZE) (SIZEID, GAMEID)
insert into gamesize values (1, 1)
insert into gamesize values (2, 2)
insert into gamesize values (2, 3)
First, you should really move on from the LINQ to SQL syntax. The EF syntax is much easier and readable. For example:
var result = db.Games.Include("GameSize.Size.Product").Select(m => m.Size.Name);
Second, All doesn't do what you seem to think it does. It returns a boolean: true if all the items match the condition, false if not. It's very unlikely that all your GameSizes have the same Size.Name. You might be looking for Any here.
Third, this whole thing seems counter-intuitive. You're getting all the games and selecting all the size names. Then using that list of size names, to select games that have those size names. In other words, you're doing an extra query to get the results you already had. Remove the select from the result and use that for games instead.
Long and short, if I'm understanding your code properly, you can reduce all of this to just one simple line:
games = db.Games.Include("GameSize.Size.Product");

How to use Linq to find dates in listed but not in another

I have two list objects: one describes a list of shifts and another that describes a list of sick leave.
What I am trying to do is compare the two lists and return a result that just gives a list of sick leave, where the dates in sick-leave is not in the list of shifts.
I have written this code, but it does not return a list:
var nonAvailableDates =availability
.Where(a=>! shiftDay.Any(b=>b.ShiftDate.Date == a.StartPeriod.Date)).ToList();
Can someone please show me where I have gone wrong?
Thanks
You're looking for the set difference operation, which is the Except() method in LINQ (will give you all elements in first collection that are not in second):
List<DateTime> shifts = new List<DateTime>{ DateTime.Parse("1/1/2014"), DateTime.Parse("1/2/2014")};
List<DateTime> sickLeaves = new List<DateTime>{DateTime.Parse("1/1/2014"), DateTime.Parse("1/3/2014")};
var sickLeavesThatAreNotAlsoShifts = sickLeaves.Except(shifts); // contains only 1/3/2014
EDIT: Give this a shot. We're basically joining and then taking the items which don't have any match.
var sickLeavesNotInShifts = from sickLeave in sickLeaves
join shift in shifts on sickLeave.StartPeriod equals shift.ShiftDate into joinedShifts
from js in joinedShifts.DefaultIfEmpty()
where js == null
select sickLeave;
Note: This is asymptotically better than doing nested searches, since join internally implements a hash join, which is O(m+n) (m and n being the counts for the two collections).

Mysql nested subquery

I have a page that I'm trying to spice up a bit..
Basically my current SQL select is generated randomly from options chosen on a page.
However, I'd like the default sort order to be random; but from what I've read, I should avoid both nested subqueries in MySql, and order by rand.
But, what if I order by rand the limited number of records returned (less than 50?) with a nested subquery.
Is this a bad idea? And would this be a problem with a larger table of say 2kk + rows?
Here's what I'm thinking of doing
select * from (
select a.*,b.*
from a
left join b on b.id=a.id
where a.isactive AND etc etc
order by a.id DESC // select say page 2 of 50 newest records
limit 50,50
) tblrand order by rand() // randomize the order of those 50 records
**EDIT***
changed the inner order by a.displayorder to order by a.id DESC to better reflect the situation since the default sort order (if none specified) is newest records (ie... id sorted desc order)
and added some comments
*** SOLVED ***** (however i'd still like to know how this would pan out.. ie. how bad would it be performancewise for mysql... tnx in advance)
tnx dbsman.. i was thinking of the problem in a different way.
at first i wanted totally random rows, which as i explained would be a pain in the butt... (i got mixed up in what i wanted to do myself :)
but i think i found a solution that works like a charm with my problem doing it in the application side
//code that gets **Dataset ds** goes here
var rand = new Random();
var result = ds.Tables[0].AsEnumerable().OrderBy(r => rand.Next());
lst.DataSource = result.CopyToDataTable();

Linq Where Contains ... Keep default order

I have a collection of ID numbers that I wish to return some object for, I'm doing it by using a linq statement with a where that's using a contains statement:
var recentCats = (from i in EntityCache.Default.GetAll<Categories>()
where WebProfile.Current.RecentlyCreatedCategories.Contains(i.Id)
&& BoundCategory.ParentItemClass.Id.Equals(i.ParentItemClass.Id)
select new CategoryInfo()
{
Category = i,
ClassId = i.ParentItemClass.Id,
ClassImage = NamedResourceManager.GetResourceBinary(i.ParentItemClass.NameResourceId)
});
This works perfectly fine, except that I want to keep the order of items in the returned collection the same as they were in the list that goes in. So for example if I had a list of IDs: 14, 603, 388, I want the objects that come back to be in the same order, not the order that they're returned by the cache. Is there any way in entity framework to do this, or any way to do it that doesn't involve me writing a foreach loop?
Thanks
The Where Linq extension as with most extensions maintains the original order of the list.
Do LINQ's Enumerable Methods Maintain Relative Order of Elements?
As long as you do not explicitly reorder or use an operator that naturally would reorder the original list's order should be maintained. Obviously reordering the list for a where statement would be unneeded overhead.
The reason the information above does not apply to this question is in the comments bellow.
I would suggest changing the output of the select to be a key/value pair, where the key is the index of the Id in your list, and the value is your new object, then orderBy the key on the resulting set, and select the value.
For anyone interested, I was able to get them to come out in the same order as the list by joining them, as mentioned by Ray in the comments above.
var recentCats = (from i in WebProfile.Current.RecentlyCreatedCategories
join b in allCats
on i equals b.Id
where BoundCategory.ParentItemClass.Id.Equals(b.ParentItemClass.Id)
select ...
Thanks again for all your help & answers.

Linq to sql group by a number of records

Is there a way to create a linq to sql query to group by a Take parameter?
For instance if I have a Table that has 20 records with one unique ID value from 1 to 20, i would like to get a group of records grouped by 5 records:
Group 1: 1,2,3,4,5
Group 2: 6,7,8,9,10
....
I can think of two ways to do this
By making 5 queries:
The first query to count the total records, and the next 4 queries would be select queries where i skip 5 and take 5.
And by making one query, looping trough the results with an inner index and creating objects with the groups of 5
Is there a more elegant way to do this with linq to sql?
Your second idea is exactly what I would do. Just get everything from the database and loop on the .NET side. Probably there are ways to use Aggregate to do it in a more LINQ-esque way but I am sure they will be harder to read. If you do it in a lazy fashion (use yield to implement enumerator) you will still loop through the sequence only once so you will not lose performance.
If you're going to end up retrieving all the records from the database anyways, why not just go ahead and do it then use something like this:
collection.GroupBy(x => collection.IndexOf(x) / 5);
Can you group like this
var items = from i in arr
let m = i / 5
group i by m into d
select new { d };
If you had 10 elements it will create two groups of 5 each
Pull your data as-is, feed it to the container then split em up.
Your queries should never, ever be aware of anything concerning how the data they pull is shown to the user.

Categories

Resources