views:

98

answers:

4

I have a table in my database representing releases of software; the relevant columns of the schema being as follows:

ProductID   int
PlatformID  tinyint
Date        datetime

All are not null, and there is also a unique key assigned to the first two columns.

I would like to build a query (using LINQ) which returns the latest release (e.g. Date) for each platform (PlatformID), but no more than one record per platform (PlatformID), and is sorted by Date descending.

How can I do this?


EDIT: Here is the solution I used:

var product = ...;

var latestReleases = product.Releases
    .GroupBy(p => p.PlatformID)
    .Select(group => group.OrderByDescending(p => p.Date).FirstOrDefault())
    .OrderByDescending(release => release.Date)

for clarity...

foreach (var release in latestReleases)
{
    Console.WriteLine("The latest release of MyProduct for {0} is {1}.",
        release.PlatformID, // of course this would be a string in real code ;)
        release.Version);
}
+2  A: 

I think the following code does what you’re asking for:

var latestProducts = db.Releases
    .GroupBy(p => p.PlatformID)
    .Select(grp => new {
        Platform = grp.Key,
        Latest = grp.OrderByDescending(p => p.Date).FirstOrDefault()
    })
    .OrderByDescending(entry => entry.Latest.Date);

foreach (var entry in latestProducts)
{
    Console.WriteLine("The latest product for platform {0} is {1}.",
        entry.Platform,
        entry.Latest.ProductID);
}

Here’s how it works:

  • First, take all the products
  • Group them into groups by common PlatformID
  • Within each group, sort the products in that group by date descending and pick the first (that’ll be the one with the latest date)
  • For each group, create an object containing the PlatformID and the platform’s latest Product
  • Sort this list of objects by date descending.
Timwi
Timwi, thanks very much for your help. While your answer wasn't entirely correct (I think you are trying to get the most recently released product for platform X, whereas I wanted the most recent release of product X for each platform), I have still accepted it as I was able to use it as the basis for the code I used which is in my above post. Come to think of it, your code could be useful for an advertisement... "Check out our latest release for <platform>!" ;)
Jake Petroules
@Jake Petroules: Thanks. By and large my code is correct; I just couldn’t have known about your schema structure surrounding products and releases. Your question didn’t state it. So I assumed there was a single `Products` table containing all the releases.
Timwi
Yes, I should have been a little more specific, sorry. ;)
Jake Petroules
A: 

If you are using LINQ to Entities, LINQ to SQL, etc, then just use First() or FirstOrDefault(), they will be smart enough to limit the query to 1. If you prefer to be more explicit, you can add Take(1) to your query.

Matt Greer
although true, doesn't address the actual question
Scott Weinstein
A: 
                from plat in 
                (
                    from p in Products
                    group p by p.PlatformID
                )

                let latestRelease = 
                (
                    from p in plat
                    orderby p.Date descending
                    select p
                ).FirstOrDefault()

                where latestRelease != null

                select new 
                {
                    PlatformID = plat.Key,
                    LatestProductID = latestRelease.ProductID,
                    LatestDate = latestRelease.Date
                }
Fyodor Soikin
A: 

One line code:

IEnumerable<Product> products = AllProducts.GroupBy(p => p.PlatformID, 
    (pid, source) => source.Where(p => p.PlatformID == pid).OrderByDescending(p => p.Date).FirstOrDefault());
Danny Chen
One line code... and very hard to read.
Timwi
Well, I think it's really not so hard to read if you are familiar with this overload method.
Danny Chen