My data is as under in two tables
Master Columns
ID MyDateTime
1 07 Sept
2 08 Sept
MyDatetime column in above has unique index
Detail Columns
ID Data1 Data2 Data3
1 a b c
1 x y z
1 f g h
2 a b c
I want to populate this in a dictionary. I have tried
Dictionary<DateTime, List<Detail>> result = (
from master in db.master
from details in db.detail
where (master.ID == detail.ID)
select new
{
master.MyDateTime,
details
}).Distinct().ToDictionary(key => key.MyDateTime, value => new List<Detail> { value.details });
I expect two rows in the dictionary
1, List of 3 rows as details
2, List of 1 row as details
I get an error where it complains about the key of the dictionary entered twice. The key would be the datetime which is unique in the master
This is precisely what lookups are for - so use ToLookup instead of ToDictionary:
ILookup<DateTime, Detail> result =
(from master in db.master
join details in db.detail on master.ID equals detail.ID
select new { master.MyDateTime, details })
.ToLookup(pair => pair.MyDateTime, pair => pair.details);
(You shouldn't need to use Distinct, and note the use of a join instead of a second from and a where clause.)
Related
There are A and B tables that are related to each other. I want to create a linq query that will update the Status value in the A table if the entire row of relationship lines with the AID column in the B table is equal to or smaller than today's date in the Date field.
For example, according to the table below, the Status values of the rows with ID value 1 (AAA) and 2 (BBB) in Table A will be 1. Its Status value will not change because the line with ID value 3 (CCC) is not smaller than the current date of all the related rows in the B table.
How can I write the most stable and performance linq query?
Today : 2018-7-10
A Table
ID Name Status
1 AAA 0
2 BBB 0
3 CCC 0
B Table
ID AID Date
6 1 2018-5-3
7 2 2018-6-2
8 2 2018-6-4
9 3 2018-10-12
10 3 2018-7-7
Grouping TableB on AID
Selecting the "Max" date in each group.(Each unique AID)
Compares the selected dates with the corresponding Id in Table A.
Sets the Status value to true if the date is less or equal to the current date.
TableB.GroupBy(x => x.AId).Select(group => new { identifier = group.Key, MaxDate = group.Max(m => m.Date) }).ToList().ForEach(y =>
{
if (y.MaxDate <= DateTime.Now.Date)
{
TableA.Where(g => g.Id == y.identifier).First().Status = true;
}
});
This will select AIDs from Table B where Date is samller than now.
we select records from table A where its ID is in List from
previous step
Then we update Status value
A.Where ( a => B.Where( b => b.Date <= DateTime.Now).Select(b => b.AID).Contains(a.ID)).ForEach( a => a.Status = 1 )
/*Fetching those aS Who meet the condition. */
var aList1=(from b in dbset.Bs.Where(x=>x.Date<DateTime.Now)//TimeZone may vary
join a in dbSet.As
on b.AID equals a.ID
select a);
/*Fetching those aS Who don't meet the condition. */
var aList2=(from b in dbset.Bs.Where(x=>x.Date>=DateTime.Now)//TimeZone may vary
join a in dbSet.As
on b.AID equals a.ID
select a);
/*Removing those aS from list1 which occured in list2 */
var aFinalList=(aList1.Except(aList2)).ToList();
/*Updating status */
aFinalList.ForEach(x=>x.Status=1);
aFinalList.SaveChanges();
You can use GroupJoin extension in Lambda to Join the A and B tables then use All extension with your condition (date <= Today or any condition) then update the Status. Something like,
var lstResult = lstA.GroupJoin(lstB, a => new { a.Id }, b => new { Id = b.AId }, (a, b) => new { a, b })
.Select(x =>
{
if (x.b.All(y => y.Date <= DateTime.Now)) //Actual condition here.
{
x.a.Status = true;
return x.a;
}
else return x.a;
});
C# fiddle with sample data.
I have data table (DOCs, which is the DBSet in my context) with below data
ID Code Rev
1 A1 1
2 A1 2
3 A1 3
4 A3 1
5 A2 1
6 A2 2
I need to select the records which has a records for each Code which has the highest Rev. My expected result is
ID Code Rev
3 A1 3
6 A2 2
4 A3 1
The ID column is the PK of the table and Code+Rev is unique.
Note: There are other fields in the table which i need to get for the result. Ideal would be to get a iqueryable (Doc is the model class), i was think of selecting the ID within an inner query and then use that to get the iqueryable of docs.
Thanks in Advance
Try this:
var res = from r in DOCs
where (from c in DOCs
group c by c.Code into g
select new {
localCode = g.Key,
localRev = g.Max(t => t.Rev)
}).Any(x => x.localCode == r.Code && x.localRev == r.Rev)
select r;
res is IQueryable.
I have table data as:
Fname Lname Date ForeignKey
A B 2012-01-01 1
A B 2012-11-01 1
A B 2013-12-25 1
C K 2009-01-01 2
C K 2001-11-01 2
C K 2011-12-25 2
My table is referred as ABC in EF
So I want to group them by Foreign Key, and I am able to do that by using this query, but How to get the details of each row now?
var q = from abc in context.ABC
group abc by abc.ForeignKey into g
join efg in context.EFG on g.Key equals efg.AppId
select new
{
MortgId = g.Key,
TrackingDate = g.Max(val => val.Date),
Fname=g.?,
Lname=g.?,
Sale=efg.SalesAmount
};
foreach(var result in q)
{
if(result.Fname=="A")
{
}
}
It returns me the list.
This gives me the Record of maximum date but I want to get the details of Fname and Lname of this Maximum Date and I am not able to get any clue.
UPDATE:
The result should be like this:
Fname Lname Date ForeignKey
A B 2013-12-25 1
C K 2011-12-25 2
I want to get the details against the maximum date.
NEW UPDATE:
So I want to check on the basis of Fname and I have made a question mark that how to get the Fname of the maximum date result.
I hope it is clear now.
Get object which has max date for each group by ordering by descending, and get first:
var list = context.ABC.GroupBy(abc => abc.ForeignKey)
.Select(g => g.OrderByDescending(a => a.Date).First())
Then you can get other properties easily:
foreach (var abc in list)
{
var fname = abc.Fname;
var lname = abc.Lname;
}
My database is as follows :
ID Date Number NumberIWishToRecord
What I wish to do is use a Linq-to-SQL query to populate an ObservableCollection<ObservableCollection<CustomClass>>.
What I want is select only the rows were Number == a given parameter.
ID refers to a person, what I want to do is get all the information about a person and store it in an ObservableCollection, so I will have an ObservableCollection<CustomClass>, with each CustomClass holding information about only one row, and each ObservableCollection<CustomClass> holding information about only one person (recorded on different days).
I then wish to select an ObservableCollection of the ObservableCollection<CustomClass> which will hold information on all people!
So, some sample data :
ID Date Number NumberIWishToRecord
1 27-06-2012 0.1933 25
1 28-06-2012 0.1933 27
1 29-06-2012 0.1933 29
2 14-06-2012 0.1933 412
2 15-06-2012 0.1741 321
So when I run my method, I want to return only the Numbers of the given parameter, in my case I will choose 0.1933.
I then want both rows where ID = 1 to be saved in an ObservableCollection<CustomClass>, and the single row where ID == 2 to be saved in another ObservableCollection<CustomClass>. Then, both of these ObservableCollections will be held in their own ObservableCollection! To illustrate :
ObservableCollection<ObservableCollection<CustomClass>>
ObservableCollection<CustomClass>
1 27-06-2012 0.1933 25
1 28-06-2012 0.1933 27
1 29-06-2012 0.1933 29
ObservableCollection<CustomClass>
2 14-06-2012 0.1933 412
How would I write a query in linq to sql that would do this ?
I'll just write a standard query syntax Linq expression to achieve this, you adapt it for your tables.
var rowsById = new ObservableCollection<ObservableCollection<row>>(
from r in _rows
where r.number == 1.2
group r by r.ID into rowIdGroup
select new ObservableCollection<row>(rowIdGroup));
If you need to convert data from the row into the CustomClass:
var rowsById = new ObservableCollection<ObservableCollection<CustomClass>>(
from r in _rows
where r.number == 1.2
group r by r.ID into rowIdGroup
select new ObservableCollection<CustomClass>(
rowIdGroup.Select(r => new CustomClass
{
ID = r.ID,
Number = r.number // add more
})));
Or if you prefer query syntax in all the expression:
var rowsById = new ObservableCollection<ObservableCollection<CustomClass>>(
from r in _rows
where r.number == 1.2
group r by r.ID into rowIdGroup
select new ObservableCollection<CustomClass>(
from gr in rowIdGroup select new CustomClass
{
ID = gr.ID,
Number = gr.number
}));
This question already has answers here:
How to get first record in each group using Linq
(7 answers)
Closed 5 years ago.
Summary: How to get top 1 element in ordered groups of data
I am trying to group by a CarId field , and then within each group, I want to sort on a DateTimeStamp field descending. The desired data would be for each Car give me the latest DateTimeStamp and only that 1 in the group.
I can get to this point, but having problems taking the top 1 off of the group and ordering the group by DateTimeStamp desc.
Here is what I have after the first group operation:
group 1
------------------------
CarId DateTimeStamp
1 1/1/2010
1 1/3/2010
1 3/4/2010
group 2
------------------------
CarId DateTimeStamp
2 10/1/2009
2 1/3/2010
2 9/4/2010
what I would desire only the top 1 in an ordered group
group 1
------------------------
CarId DateTimeStamp
1 3/4/2010
group 2
------------------------
CarId DateTimeStamp
2 9/4/2010
Brickwall: Where I get stopped, is needing the CarId and DateTimeStamp in the group by clause, in order to later sort by the DateTimeStamp. Maybe the sorting of the date should be done in a separate function, not sure.
data
.GroupBy(
x => x.CardId,
(x, y) => new {
Key = x,
Value = y.OrderByDescending(z => z.DateTimeStamp).FirstOrDefault()
}
);
This will group all the elements by CardId, then order the elements of each group by DateTimeStamp (descending), then pare down each group to only contain the first element. Finally, it returns an enumerable of "groups" (with the scare quotes since they're actually an anonymous type instead of an IGrouping) where each group has the one item you're seeking.
I find the query expression syntax easier to understand myself:
from x in data
group x by x.CarId into grp
select new {
CarId = x.CarId,
Record = (from x in grp orderby z.DateTimeStamp descending).FirstOrDefault()
};