I was wandering if someone can explain to me why this query doesn't act like the SQL Left join, I cant seem to work out why. I have been doing a bit of hunting and I can't seem to work it out. As far as I can tell it should.
I.e. In a table with 5 Active Customers it will only return 2 of those Customers instead of all 5; 2 with values and 3 with either null or 0?
var results = from c in DataContext.Customers
where c.Active
join j1 in
(from i in DataContext.Invoice where i.State== "Pending" &&
i.InvoiceDate.Date >= From.Date && i.InvoiceDate.Date <= To.Date
group i by i.Customer into x
select new { x.Key, Total = x.Count() }) on a equals j1.Key
select new { c, j1.Total };
Thanks
By using DefaultIfEmpty() method you can do it.
Try this code
i have implementd your problem's solution
revert me if it worked
var results = from c in DataContext.Customers
where c.Active
join j1 in
(from i in DataContext.Invoice where i.State== "Pending" &&
i.InvoiceDate.Date >= From.Date && i.InvoiceDate.Date <= To.Date
group i by i.Customer into x
select new { x.Key, Total = x.Count() }) on a equals j1.Key into j3
from k in j3.DefaultIfEmpty()
select new { c, k.Total };
I would try DefaultIfEmpty() method on your j1 subquery, because you aren't allowing the query to join on null values.
See the similar question for examples.
Related
I have a two tables Customers, and ConnectedCustomers. That means customers can connect with each other.
My question is how can I get all Customers which are related to Chris (id = 3).
I should as a results get Bob and John..
I've tried something like this:
query = _context.Customers.Where(c =>_context.ConnectedCustomers.Any(cc => cc.Connected_Customer1.Equals(3) || cc.Connected_Customer2.Equals(3)));
But this is not working it returns too many rows..
Expected result for id 3 is BOB AND JOHN because they are connected
with id 3.
Thanks guys
Cheers
var answer = (from cc in _context.ConnectedCustomers
join c1 in _context.Customers on cc.Connected_Customer1 equals c1.id
join c2 in _context.Customers on cc.Connected_Customer2 equals c2.id
where c1.id == 3 || c2.id == 3
select c1.id == 3 ? c2 : c1
).ToList();
The problem in your query is you are querying from Customer table. When you are querying through Customer, what it's doing is getting all the possible combinations of Fk with Connected_Customer1 and Connected_Customer2 which satisfies the condition.
What you should be doing is query from ConnectedCustomers.
Try this:
var result = _context.ConnectedCustomers
.Where(x => x.Connected_Customer1.Equals(3) || x.Connected_Customer2.Equals(3))
.Select(x=>x.Customers)
.ToList();
You never use the id of the user to check (c), so you have to add a condition like this :
var query = _context.Customers.Where(customer => _context.ConnectedCustomers.Any(cc =>
cc.Connected_Customer1.Equals(customer.Id) && cc.Connected_Customer2.Equals(3) ||
cc.Connected_Customer1.Equals(3) && cc.Connected_Customer2.Equals(customer.Id))).ToList();
_context.Customers.Where(c => c.Id == _context.ConnectedCustomers.Where(cc => cc.Connected_Customer1 == 3).Select(cc => cc.Connected_Customer2))
Try that.
I have multiple customers that are a part of a group designated by a group id.
I would like to retrieve 1 record from a related table for each of the matching group members (last record before a certain date).
Currently I query for a list of group members then for each member i run another query to retrieve last record from a date.
I would like to do this with one query since i can pull up the associated table records using group id - however this returns all the records associated to group (bad).
If i use first or default i only get results for first group found.
I want 1 record from each group member.
My Code (returns all associated records of group members):
List<Record> rs = (from x in db.Records where (x.Customer.Group == udcg && x.CloseDate < date && x.CloseDate < earlyDate) orderby x.CloseDate descending select x).ToList();
But i just want one from each instead of all.
Code I use now:
var custs = (from x in db.Customers where (x.group == udcg) select new { x.CustomerID }).ToList();
expected = custs.Count();
foreach (var cust in custs)
{
Record br = (from x in db.Records where (x.Customer.CustomerID == cust.CustomerID && x.CloseDate < date && x.CloseDate < earlyDate)) orderby x.CloseDate descending select x).FirstOrDefault();
if (br != null)
{
total = (double)br.BillTotal;
cnt++;
}
}
I think this could work
db.Customers
.Where(c => c.group == udcg)
.Select(c => db.Records
.Where(r => r.Customer.CustomerID == c.CustomerID)
.Where(r => r.CloseDate < date)
.Where(r => r.CloseDate > date.AddMonths(-2))
.OrderByDescending(r => r.CloseDate)
.FirstOrDefault())
.Where(r => r != null)
It is translated into one sql query. That means it uses one roundtrip to the server. That could be quite a big difference in performace when compared to the foreach loop. If you look at the generated sql, it would be something like
SELECT some columns
FROM Customers
OUTER APPLY (
SELECT TOP (1) some columns
FROM Records
WHERE some conditions
ORDER BY CloseData DESC
)
In terms of performace of the query itself, I would not expect problems here, sql server should not have problems optimizing this form (compared to other ways you could write this query).
Please try this one, evaluate records list.
DateTime certain_date = new DateTime(2018, 11, 1);
List<Record> records = new List<Record>();
var query = records.GroupBy(x => x.Customer.Group).Select(g => new { Group = g.Key, LastRecordBeforeCertainDate = g.Where(l => l.CloseDate < certain_date).OrderByDescending(l => l.CloseDate).FirstOrDefault() });
I am creating a LINQ statement like following
from c2 in context.AspNetRoles
join c1 in context.RoleActions
on c2.Id equals c1.RoleId
where c2.UserId == System.Web.HttpContext.Current.User.Identity.GetUserId()
select new { c2.Name };
Notice that c2 appears first. The problem is the
c2.UserId
is not showing in intelligence. Is this a common behavior in LINQ. how can I fix the above LINQ statement, order is important?In where clause with join should have table identifier in the last in joining?
Thanks
If i understand you well...
You can mix standard notation of query with lambda. So, if you want to filter context.AspNetRoles then join context.RoleAction, you can try something like that:
var result = from c2 in context.AspNetRoles.Where(x=>x.Field=="SomeValue"
&& x.UserId == System.Web.HttpContext.Current.User.Identity.GetUserId())
join c1 in context.RoleActions on c2.Id equals c1.RoleId
select new { c2.Name };
Why join if you need only one value? Maybe try something like this:
var result = context.AspNetRoles
.Where(o => context.RoleActions.Any(oo => oo.RoleId == o.Id) &&
o.UserId == System.Web.HttpContext.Current.User.Identity.GetUserId())
.Select(o => o.Name)
.ToList();
I'm getting a problem with a query with linq in EF.
Basically, what i'm tring to do is this, in plain SQL:
SELECT
t2.*
FROM
[SHP_Console2].[dbo].[Domain] t1
INNER JOIN
[SHP_Console2].[dbo].[Domain] t2
ON t2.[left] >=t1.[left] AND t2.[right]<=t1.[right]
WHERE
t1.ID =1
I'm not able to do this with linq.
I'm tring this:
from a in DomainRep.Where(c => c.ID == domainID).Select(c => new { c.left, c.right })
from b in DomainRep.Where(x => x.left >= a.left && x.right <= a.right)
select a;
What i'm doing wrong?
You mixed your query with anonymous types. You can't do that this way.
You also can't use JOIN with >= condition - LINQ does not support that kind of statements. However, it can be done using alternative syntax.
from a in DomainRep
from b in DomainRep
where b.left >= 1.left && b.right <= a.right && a.ID = 1
select b;
Edit: Reference: http://social.msdn.microsoft.com/Forums/en-US/linqprojectgeneral/thread/428c9db2-29f6-45d8-ab97-f00282397368/
var query = (from a in DomainRep
from b in DomainRep
where a.left >= b.left
select b)
.ToList();
I'm using LINQ on an IQueryable returned from NHibernate and I need to select the row with the maximum value(s) in a couple of fields.
I've simplified the bit that I'm sticking on. I need to select the one row from my table with the maximum value in one field.
var table = new Table { new Row(id: 1, status: 10), new Row(id: 2, status: 20) }
from u in table
group u by 1 into g
where u.Status == g.Max(u => u.Status)
select u
This is incorrect but I can't work out the right form.
BTW, what I'm actually trying to achieve is approximately this:
var clientAddress = this.repository.GetAll()
.GroupBy(a => a)
.SelectMany(
g =>
g.Where(
a =>
a.Reference == clientReference &&
a.Status == ClientStatus.Live &&
a.AddressReference == g.Max(x => x.AddressReference) &&
a.StartDate == g.Max(x => x.StartDate)))
.SingleOrDefault();
I started with the above lambda but I've been using LINQPad to try and work out the syntax for selecting the Max().
UPDATE
Removing the GroupBy was key.
var all = this.repository.GetAll();
var address = all
.Where(
a =>
a.Reference == clientReference &&
a.Status == ClientStatus.Live &&
a.StartDate == all.Max(x => x.StartDate) &&
a.AddressReference == all.Max(x => x.AddressReference))
.SingleOrDefault();
I don't see why you are grouping here.
Try this:
var maxValue = table.Max(x => x.Status)
var result = table.First(x => x.Status == maxValue);
An alternate approach that would iterate table only once would be this:
var result = table.OrderByDescending(x => x.Status).First();
This is helpful if table is an IEnumerable<T> that is not present in memory or that is calculated on the fly.
You can also do:
(from u in table
orderby u.Status descending
select u).Take(1);
You can group by status and select a row from the largest group:
table.GroupBy(r => r.Status).OrderByDescending(g => g.Key).First().First();
The first First() gets the first group (the set of rows with the largest status); the second First() gets the first row in that group.
If the status is always unqiue, you can replace the second First() with Single().
Addressing the first question, if you need to take several rows grouped by certain criteria with the other column with max value you can do something like this:
var query =
from u1 in table
join u2 in (
from u in table
group u by u.GroupId into g
select new { GroupId = g.Key, MaxStatus = g.Max(x => x.Status) }
) on new { u1.GroupId, u1.Status } equals new { u2.GroupId, Status = u2.MaxStatus}
select u1;
What about using Aggregate?
It's better than
Select max
Select by max value
since it only scans the array once.
var maxRow = table.Aggregate(
(a, b) => a.Status > b.Status ? a : b // whatever you need to compare
);
More one example:
Follow:
qryAux = (from q in qryAux where
q.OrdSeq == (from pp in Sessao.Query<NameTable>() where pp.FieldPk
== q.FieldPk select pp.OrdSeq).Max() select q);
Equals:
select t.* from nametable t where t.OrdSeq =
(select max(t2.OrdSeq) from nametable t2 where t2.FieldPk= t.FieldPk)
Simply in one line:
var result = table.First(x => x.Status == table.Max(y => y.Status));
Notice that there are two action.
the inner action is for finding the max value,
the outer action is for get the desired object.