LINQ: Drill down to value in query results - linq

I am using LINQ for the first time and have the following query:
var query = from c in context.Call
join d in context.CallData on c.CallID = d.CallID
where c.CallID == 123
select new {
c.CallID,
c.CallResult,
d.FieldID,
d.FieldValue
};
This returns data similar to the following
c.CallID c.CallResult d.FieldID d.FieldValue
123 Sale 345 John
123 Sale 346 Doe
123 Sale 347 888-222-3333
How can drill down to the row containing d.FieldID = 346 to get the value of d.FieldValue (346 being the LastName field)? I would like to use this value as the new value of a local variable:
// I know this doesn't work, just showing what I would like to accomplish
string LastName = query.Select(a => a.FieldID = 346).FieldValue;
Conversely, how can I change the value of c.CallResult once I have these results? Since it is a join, can I simply change one row of data or do I have to do a separate query?

For the first question you can move on from your query variable:
var fieldValue = query.Where(x => x.FieldID == 346).Single().FieldValue;
As for your second question: you must apply a change to the original entity object:
var call = context.Find(123);
// or context.Calls.Single(c => c.CallId == 123) if this is not DbContext.
call.CallResult = newValue;
context.SaveChanges();

Do you mean:
string LastName = query
.Where(a => a.FieldID = 346)
.Select(a => a.FieldValue)
.FirstOrDefault();

Related

Get distinct value from database

I want to get the distinct list of studentname from the database who are still active. Ihis is what I've tried.
string strJSON = JsonConvert.SerializeObject(
context.Students.Where(x => x.IsActive == 1).Distinct().ToList());
Distinct function works on all columns, so I assume that you want only student name.
string strJSON = JsonConvert.SerializeObject(
context
.Students
.Where(x => x.IsActive==1)
.Select(x=>x.StudentName)
.Distinct()
.ToList()
);

How to get a list of the grouped values in linq groupby?

Linq newbie here, struggling with my first GroupBy query.
I have a list of objects of type KeywordInstance which represents a keyword, and the ID of the database record to which the keyword was applied.
Keyword RecordID
macrophages 1
macrophages 2
cell cycle 3
map kinase 2
cell cycle 1
What I want is a collection of all keywords, with a list of the RecordIDs to which each keyword was applied.
Keyword RecordIDs
macrophages 1, 2
cell cycle 1, 3
map kinase 2
I tried using Linq to get it into a new object. I only managed to get the distinct keywords.
var keywords = allWords
.GroupBy(w => w.keyword)
.Select(g => new {keyword = g.Key});
The problem is that I can't seem to get the values of g in any way. g is of the type IGrouping<String, KeywordInstance> and by documentation, it only has the property Key, but not even the property Value. All the examples I have seen on the Internet for groupby just tell me to select g itself, but the result of
var keywords = allWords
.GroupBy(w => w.keyword)
.Select(g => new {keyword = g.Key, RecordIDs = g});
is not what I want.
Any try to get something out of g fails with the error message System.Linq.IGropuing<string, UserQuery.KeywordInstance> does not have a definition for [whatever I tried].
What am I doing wrong here?
I think you are close to you solution.
var keywords = allWords
.GroupBy(w => w.keyword)
.Select(g => new
{
keyword = g.Key,
RecordIDs = g.Select(c => c.ID)
});
Just Select the records you need.
The reason you are seeing the Keyword-column as well as the ID-column, is becuase it's part of g
var keywords = allWords.GroupBy(w => w.keyword);
foreach (var itm in keywords)
{
var list = itm.ToList();
//list returns all of the original properties/values objects from allwords.
//itm.key returns w.keyword
}

When is OrderBy operator called?

1)
a)
var result1 = from artist in artists
from album in artist.Albums
orderby album.Title,artist.Name
select new { Artist_id = artist.id, Album_id = album.id };
Is the above query translated into:
var result = artists.SelectMany(p => p.albums
.Select(p1 => new { Artist = p, Album = p1 }))
.OrderBy(p2 => p2.Album.Title)
.ThenBy(p3 => p3.Artist.Name)
.Select(p4 => new { Artist_id = p4.Artist.id, Album_id = p4.Album.id });
b)
I'm not sure if this question will make much sense - If my assumptions are correct and thus OrderBy is always one of the last operators to get called ( when using query expression ), then how would we express the following code using query expression (in other words, how do we specify in a query expression that we want OrderBy operator to get called sooner and not as one of the last operators ):
var result = artists
.SelectMany(p1 => p1.albums
.OrderBy(p2=>p2.title)
.Select(p3 => new { ID = p3.id, Title = p3.title }));
2) Do in the following query expression the two orderby clauses get translated into OrderBy(... artist.Name).OrderBy( ... album.Title):
var result1 = from artist in artists
from album in artist.Albums
orderby artist.Name
orderby album.Title
select new { ...};
thank you
For question 1: orderby gets called wherever you show it. Your query isn't quite equivalent to what you showed, but it's close. It doesn't help that you formatted it so that it looks like the Select is called on the result of SelectMany, when it's actually on the arguments to SelectMany. Your query is translated to something more like:
var result = artists
.SelectMany(artist => artist.albums, (artist, album) => new {artist, album})
.OrderBy(z => z.album.Title)
.ThenBy(z => z.artist.Name)
.Select(z => new { Artist_id = z.artist.id, Album_id = z.album.id }
Question 1b) Your query is roughly equivalent to:
var result = from p1 in artists
from p3 in (from p2 in p1.albums
orderby p2.title
new { ID = p2.id, Title = p2.title })
select p3;
It's only a rough translation as nothing in query expressions is converted to that overload of SelectMany, as far as I can remember. On the other hand, it could be that this does what you want in a slightly simpler way:
var result = from p1 in artists
from p3 in p1.albums.OrderBy(p2 => p2.title)
select new { ID = p3.id, Title = p3.title };
You'll still get the ordering within the artist. It's a mixture of query expression and "dot notation", but it looks good to me. Odd that you're not using p1 in the final result, mind you...
For question 2, using two orderby clauses you do indeed get two OrderBy calls, which is almost certainly not what you want. You want:
var result1 = from artist in artists
from album in artist.Albums
orderby artist.Name, album.Title
select new { ...};
That gets translated into the appropriate OrderBy(...).ThenBy(...) calls.

What's the LINQ to select the latest item from a number of versioned items?

I've got a class like the following:
public class Invoice
{
public int InvoiceId {get;set;}
public int VersionId {get;set;}
}
Each time an Invoice is modified, the VersionId gets incremented, but the InvoiceId remains the same. So given an IEnumerable<Invoice> which has the following results:
InvoiceId VersionId
1 1
1 2
1 3
2 1
2 2
How can I get just the results:
InvoiceId VersionId
1 3
2 2
I.e. I want just the Invoices from the results which have the latest VersionId. I can easily do this in T-SQL, but cannot for the life of me work out the correct LINQ syntax. I'm using Entity Framework 4 Code First.
Order by the VersionId, group them by InvoiceId, then take the first result of each group. Try this:
var query = list.OrderByDescending(i => i.VersionId)
.GroupBy(i => i.InvoiceId)
.Select(g => g.First());
EDIT: how about this approach using Max?
var query = list.GroupBy(i => i.InvoiceId)
.Select(g => g.Single(i => i.VersionId == g.Max(o => o.VersionId)));
Try using FirstOrDefault or SingleOrDefault in place of Single as well... it would give the same result although Single shows the intention better.
EDIT: I've tested both these queries with LINQ to Entities. They seem to work, so perhaps the issue is something else?
Option 1:
var latestInvoices = invoices.GroupBy(i => i.InvoiceId)
.Select(group => group.OrderByDescending(i => i.VersionId)
.FirstOrDefault());
EDIT: Changed 'Last' to 'FirstOrDefault', LINQ to Entities has issues with the 'Last' query operator.
Option 2:
var invoices = from invoice in dc.Invoices
group invoice by invoice.InvoiceId into invoiceGroup
let maxVersion = invoiceGroup.Max(i => i.VersionId)
from candidate in invoiceGroup
where candidate.VersionId == maxVersion
select candidate;
My version:
var h = from i in Invoices
group i.VersionId by i.InvoiceId into grouping
select new {InvoiceId = grouping.Key, VersionId = grouping.Max()};
Update
As was mentioned by Ahmad in the comments, the above query will return a projection. The version below will return a IQueryable<Invoice>. I use composition to build the query because I think it is more clear.
var maxVersions = from i in Invoices
group i.VersionId by i.InvoiceId into grouping
select new {InvoiceId = grouping.Key,
VersionId = grouping.Max()};
var latestInvoices = from i in Invoices
join m in maxVersions
on new {i.InvoiceId, i.VersionId} equals
new {m.InvoiceId, m.VersionId}
select i;

Groupby and where clause in Linq

I am a newbie to Linq. I am trying to write a linq query to get a min value from a set of records. I need to use groupby, where , select and min function in the same query but i am having issues when using group by clause. here is the query I wrote
var data =newTrips.groupby (x => x.TripPath.TripPathLink.Link.Road.Name)
.Where(x => x.TripPath.PathNumber == pathnum)
.Select(x => x.TripPath.TripPathLink.Link.Speed).Min();
I am not able to use group by and where together it keeps giving error .
My query should
Select all the values.
filter it through the where clause (pathnum).
Groupby the road Name
finally get the min value.
can some one tell me what i am doing wrong and how to achieve the desired result.
Thanks,
Pawan
It's a little tricky not knowing the relationships between the data, but I think (without trying it) that this should give you want you want -- the minimum speed per road by name. Note that it will result in a collection of anonymous objects with Name and Speed properties.
var data = newTrips.Where(x => x.TripPath.PathNumber == pathnum)
.Select(x => x.TripPath.TripPathLink.Link)
.GroupBy(x => x.Road.Name)
.Select(g => new { Name = g.Key, Speed = g.Min(l => l.Speed) } );
Since I think you want the Trip which has the minimum speed, rather than the speed, and I'm assuming a different data structure, I'll add to tvanfosson's answer:
var pathnum = 1;
var trips = from trip in newTrips
where trip.TripPath.PathNumber == pathnum
group trip by trip.TripPath.TripPathLink.Link.Road.Name into g
let minSpeed = g.Min(t => t.TripPath.TripPathLink.Link.Speed)
select new {
Name = g.Key,
Trip = g.Single(t => t.TripPath.TripPathLink.Link.Speed == minSpeed) };
foreach (var t in trips)
{
Console.WriteLine("Name = {0}, TripId = {1}", t.Name, t.Trip.TripId);
}

Resources