Get Distinct record in table using LINQ - c#

This is my table. I want to get the distinct records as unique Name , SourceDeviceId, SourceState, Id . Since ID column consists of unique numbers I am getting all the records. But I want to get any of Id with Same Name, SourceDeviceId, SourceState. I have tried to use GroupBy but I am not able to select specific columns after select statement.

You can do this a few ways, however this might help
var result = db.SomeTable.GroupBy(x => new
{
x.Name,
x.SourceDeviceId
})
.Select(x => x.First())
.ToList();
It gives you back a list of distinct entities by Name and SerouceDeviceId
Or if you want an anonymouse type
var result = db.SomeTable.GroupBy(x => new
{
x.Name,
x.SourceDeviceId
})
.Select(x => x.Key)
.ToList();

Consider using Distinct:
var result = db.SomeTable.Select(x => new
{
x.Name,
x.SourceDeviceId
})
.Distinct()
.ToList();
The ToList is optional - whether you need it depends on how you plan to use result.

Related

Linq OrderBy then GroupBy - group by unexpectedly changes order of list

When I run this expression i can see that the list order is correctly in sequence by the highest ActionId's
var list = db.Actions.Where(z => z.RunId
== RunId).OrderByDescending(w =>
w.ActionId).ToList();
I only want to select the highest ActionId's of each ActionName so I now do:
var list = db.Actions.Where(z => z.RunId
== RunId).OrderByDescending(w =>
w.ActionId).GroupBy(c => new
{
c.ActionName,
c.MachineNumber,
})
.Select(y =>
y.FirstOrDefault()).ToList();
When I look at the contents of list, it hasn't selected the ActionName/MachineNumber with the highest ActionId, which I assumed would be the case by ordering then using FirstOrDefault().
Any idea where I'm going wrong? I want to group the records by the ActionName and MachineId, and then pick the record with the highest ActionId for each group
Instead of grouping an ordered collection, group the collection first, and then select the record with the highest ID for each of the groups. GroupBy is not guaranteed to preserve the order in each group in LINQ to SQL - it depends on your database server.
var list = db.Actions.Where(z => z.RunId == RunId).GroupBy(c => new
{
c.ActionName,
c.MachineNumber,
})
.Select(y => y.OrderByDescending(z => z.ActionId).FirstOrDefault()).ToList();

Select all distinct last records of column1 and order by column2 in Linq (Not Working Accordingly)

So I have a table like this:
Now I want distinct ShortCode order by the ID descending. In other words, the distinct last records. Like this:
So I tried GroupBy like:
var data = db.ShortCodes.GroupBy(x => x.ShortCode).Select(x => x.FirstOrDefault()).OrderByDescending(s=> s.ID);
This gave me distinct records but not the last ones, nor ordered by ID descending:
Now I also tried like suggested here
var data = db.ShortCodeManager
.GroupBy(s => s. ShortCode)
.Select(g => g.First())
.OrderByDescending(s => s.ID);
This gave me the error The method 'First' can only be used as a final query operation. Consider using the method 'FirstOrDefault' in this instance instead.
So I modified to FirstOrDefault() like:
var data = db.ShortCodeManager
.GroupBy(s => s. ShortCode)
.Select(g => g.FirstOrDefault())
.OrderByDescending(s => s.ID);
This also gave me distinct records but not the last records:
So finally I tried like suggested here:
var data = db.ShortCodeManager.Where(a => a.ID > 0).GroupBy(x => x.ShortCode).OrderByDescending(grp => grp.Max(g => g.ID)).Select(a => a.FirstOrDefault());
Again, this gave me distinct records but not the last ones, nor ordered by ID descending:
So how am I to write the query to get the result I want in Linq? Also note, I need more of the distinct last records than ordering by ID descending. If anyone also knows how to write it in raw SQL it might be useful as well.
This LINQ query should work for your case:
var result = db.ShortCodeManager
.GroupBy(x => x.ShortCode)
.Select(gr => new { Id = gr.Max(g => g.Id), ShortCode = gr.Key})
.ToList();
EDIT:
Based on your comment it looks like you need to cast anonymous object result to ShortCodeManagerModel type and then pass it to your view. So, somethin like this:
var result = db.ShortCodeManager
.GroupBy(x => x.ShortCode)
.Select(gr => new { Id = gr.Max(g => g.Id), ShortCode = gr.Key})
.ToList();
var model = result
.Select(x => new ShortCodeManagerModel { Id = x.Id, ShortCode = x.ShortCode })
.ToList();
And then pass model to you view.

Casting Nhibernate result into IDictionary<string,int>

I am trying to convert the result of the query into IDictionary
Here string will contain orderId and the int will contain the TradedQuantity
The query below should join three objects Order, OrderRevision and OrderEvent.
1 Order can have many orderRevisions
1 OrderRevision can have many orderEvents
What the query is trying to do is to inner join three objects and get all order objects whose order id matches the list of orderids supplied to it. Then it does a group by based on orderId and gets the latest TradedQuantity from orderEvents object. LatestTradedQuantity will be the TradedQuantityFrom latest OrderEvent. For now the latest orderevent can be regarded as the one that has highest OrderEventId value.
OrderRevision revisionAlias = null;
Order orderAlias = null;
var query =
Session.QueryOver<OrderEvent>()
.JoinAlias(oe => oe.OrderRevision,() => revisionAlias)
.JoinAlias(oe => oe.OrderRevision.Order,() => orderAlias)
.Where(x => x.OrderRevision.Order.SourceSystem.Name.ToLower() == sourceSystem.ToLower())
.WhereRestrictionOn(x => x.OrderRevision.Order.Id).IsIn(orderIds.ToList())
.SelectList(list => list.SelectGroup(x => x.OrderRevision.Order.SourceOrderIdentifier)
.SelectMax(x => x.Id).Select(x => x.TradedQuantity))
.Select(x => new KeyValuePair<string, int?>(x.OrderRevision.Order.SourceOrderIdentifier, x.TradedQuantity)
);
As this query does not do what is supposed to. Could you please help and let me know how the result can be cast into IDictionary?
You have tagged your question with linq-to-nhibernate, so I guess using it instead of queryover would suit you. With Linq, use a sub-query for selecting the "max" order events ids for each order, then query them and project them to a dictionary.
using System.Linq;
using NHibernate.Linq;
...
var orderEventsIdsQuery = Session.Query<OrderEvent>()
.Where(oe => orderIds.Contains(oe.OrderRevision.Order.Id))
.GroupBy(oe => oe.OrderRevision.Order.SourceOrderIdentifier,
(soi, oes) => oes.Max(oe => oe.Id));
var result = Session.Query<OrderEvent>()
.Where(oe => orderEventsIdsQuery.Contains(oe.Id))
.ToDictionary(oe => oe.OrderRevision.Order.SourceOrderIdentifier,
oe => oe.TradedQuantity);
This should do the job. I do not use QueryOver and I will not try to give an answer for doing it with QueryOver.

Select most frequent value and count using LINQ and assign to dictionary

I'm trying to select the top five most frequent values and their count in my table and return them in a Dictionary. I'm able to get the values in sql:
SELECT top 5
SR_Status,
COUNT(SR_Status) AS 'value_count'
FROM
ServiceRequests
GROUP BY
SR_Status
ORDER BY
'value_count' DESC;
How to convert to linq and assign to Dictionary
You do not specify if you are using Linq2Sql or Linq2Objects, so, let's just assume linq then. Try something like this (see the comments for each line):
var result = (from s in ServiceRequests // define the data source
group s by s.SR_Status into g // group all items by status
orderby g.Count() descending // order by count descending
select new { g.Key, Total = g.Count() }) // cast the output
.Take(5) // take just 5 items
.ToDictionary(x => x.Key, x => x.Total); // cast to dictionary
Obs: I didn't test it.
Assuming you are using Entity Framework and have an EntitySet named ServiceRequests and all the properties names are the same as the column names:
var result = context.ServiceRequests.GroupBy(sr => sr.SR_Status)
.Select(g => new { Key = g.Key, Count = g.Count() })
.OrderByDescending(kv => kv.Count)
.Take(5)
.ToList();

Select items from list using many ids

The target is to get list of 10 popular movies.
There is a table called populars in the database that contains:
moviecount - the number of times the film was rented.
MovieID - id of the film.
There's also a table called Movies that contains all the data of the movies. This table contains a field for MovieID.
The tables are not related and should not be linked between them.
I took the 10 id's of the most popular films
var TopTen = videoLibDB.populars
.Take(10)
.OrderBy(e => e.movieCount)
.Select(e => new { e.MovieID });
This is ok, but how do I create a List of the 10 best movies from "movies" table by using 10 MovieIDs of the populars table(the TopTen of the code above)?
In case of one id I can compare the moiveid from the popular table to the movieid in the movies table.
If you have the relations set up correctly, #JimWooley's answer above is the easiest/best, this query is in case you don't have that possibility.
You have some problems in your linq query, you're taking 10 random movies and ranking only them, least popular first. This query fixes that and joins it with the movie table to get the most popular movies;
var query =
from movie in videoLibDB.movies
where
videoLibDB.populars
.OrderByDescending(x => x.movieCount) // Sort all, most popular first
.Take(10) // but only keep the 10 first
.Select(x => x.MovieID) // Take their MovieID
.Contains(movie.MovieID) // and get movie data on them
select movie;
First, make sure to sort (OrderBy) before take. In LINQ to SQL/EF, this may not be significant, but with LINQ to Objects it will result in only the first ten rows being evaluated.
Second, you need to either join your populars with the movies, or use the association between the tables. Assuming you have an association set-up, you should be able to do something like the following:
var TopTen = videoLibDB.populars
.OrderByDescending(e => e.movieCount)
.Take(10)
.Select(e => new { e.MovieID, e.Movie.MovieName});
Use .Contains
First create an array containing the IDs....
var ids = new[] { 1,2,3,4,5,6,7,8,9,10 };
Then use .Contains
var TopTen = videoLibDB.populars
.Where(e => ids.Contains(e.MovieID)
.OrderBy(e => e.movieCount)
.Select(e => new { e.MovieID });
It's the equivalent of an IN statement in T-SQL
Try this, it should generate an IN clause.
var results = from q in videoLibDB.movies
where videoLibDB.populars
.OrderBy(e => e.movieCount)
.Take(10)
.Select(e => e.MovieID)
.ToArray()
.Contains(q.MovieID)
select q
And here is an article that goes more in depth.
i don't see why you have that restriction that the tables may not be linked ... but hey...
var TopTen = videoLibDB.populars
.OrderBy(e => e.movieCount)
.Take(10)
.Select(e => e.MovieID).ToArray();
var YourActualMovies = videoLibDB.movies
.Where(x=>TopTen.Conatins(x.MovieID))
.Select(...whatever you want...)

Categories

Resources