Reputation: 1481
Happy new Year everyone ! :-)
I've searched for several hours but I can't figure out how to build my query properly using Linq.
I have 2 tables : A and B
In table A : I have A_ID, B_ID, VALUE_DATE.
In table B : I have B_ID, STATUS.
Example :
A_ID = 547 VALUE_DATE = 01/05/10 B_ID = 14750
A_ID = 547 VALUE_DATE = 01/10/10 B_ID = 14750
I want to join A and B using B_ID where VALUE_DATE is max. At the moment, this is what I have :
context is OracleDataContextCommon object evalId and listAffId are parameters of my webservice method.
var query = (from tabA in (from a in context.A
where listAffId.Contains(a.A_ID)
group a by a.A_IDinto grp
select new
{
pId = (int)grp.Key,
valDate = grp.Max(x => x.ValueDate),
bId = grp.Select(x => B_ID).FirstOrDefault()
})
join tabB in context.B on tabA.bIdequals equals tabB.B_ID
select new
{
affId = tabA.pId,
status = tabB.Status
});
Where am I wrong ? Thank you for investigate...
Upvotes: 1
Views: 876
Reputation: 34421
I simulated code with classes. I think this should work
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Context context = new Context();
List<int> listAffId = new List<int>() { 547 };
var query = (from a in context.A where listAffId.Contains(a.A_ID)
join b in context.B on a.B_ID equals b.B_ID
select new { a = a, b = b})
.GroupBy(x => x.a.A_ID)
.Select(x => new { x = x, max = x.Max(y => y.a.VALUE_DATE)})
.Select(x => new {
affId = x.x.Key,
status = x.x.Where(y => y.a.VALUE_DATE == x.max).Select(y => y.b.STATUS).FirstOrDefault()
}).ToList();
}
}
public class Context
{
public List<TableA> A { get; set; }
public List<TableB> B { get; set; }
}
public class TableA
{
public int A_ID { get; set; }
public int B_ID { get; set; }
public DateTime VALUE_DATE { get; set; }
}
public class TableB
{
public int B_ID { get; set; }
public string STATUS { get; set; }
}
}
Upvotes: 1
Reputation: 26917
You need to select the B_ID
that is for the max date, so find the max date first:
var query = (from tabA in (from a in context.A
where listAffId.Contains(a.A_ID)
group a by a.A_IDinto grp
let maxdate = grp.Max(a => a.ValueDate)
select new
{
pId = (int)grp.Key,
valDate = maxdate,
bId = grp.Where(a => a.ValueDate == maxdate).Select(x => B_ID).FirstOrDefault()
})
join tabB in context.B on tabA.bId equals equals tabB.B_ID
select new
{
affId = tabA.pId,
status = tabB.Status
});
Upvotes: 1
Reputation: 107247
The problem is that you're taking the max Date of the Group, but you are selecting the FirstOrDefault
B_ID in the group, which doesn't necessarily correlate with the A row which had the max date. Easiest is probably to just order the data by date descending before grouping, and then take the first item in each group for both date and b_id
.
Note that I've switched your context for with some dummy data below.
var theAs = new[]
{
new {A_ID = 547, ValueDate = new DateTime(2010, 05, 01), B_ID = 14750},
new {A_ID = 547, ValueDate = new DateTime(2010, 10, 01), B_ID = 14751}
};
var theBs = new[]
{
new {B_ID = 14750, Status = "Foo"},
new {B_ID = 14751, Status = "Bar"}
};
var listAffId = new[]{547};
var query = (from tabA in (from a in theAs
where listAffId.Contains(a.A_ID)
// Order the data - the first row per group is thus max date
orderby a.ValueDate descending
group a by a.A_ID into grp
select new
{
pId = (int)grp.Key,
// Now pull the date and B_ID from the same row
valDate = grp.First().ValueDate,
bId = grp.First().B_ID
})
join tabB in theBs on tabA.bId equals tabB.B_ID
select new
{
affId = tabA.pId,
status = tabB.Status
});
Upvotes: 1