Why ".Distinct() " doesn't work as expected [duplicate] - c#

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
DISTINCT() and ORDERBY issue
listOrders.DataSource = (from sp in dbdata.Specifications.Where(i => i.Approve == "Yes" && i.Awailable_BOM == "Yes")
join ord in dbdata.Orders on sp.O_id equals ord.O_id
join prd in dbdata.Products.Where(k => k.Hours_prd == null) on ord.O_id equals prd.O_ID
orderby ord.Special, sp.Due_date
select ord.O_id).Distinct();
I am tring to order by "ord.Special, sp.Due_date" but it doesn't work after I put "Distinct();". So how do I order by "ord.Special, sp.Due_date" and get distinct values.

I think this will return ordered ids:
listOrders.DataSource =
from sp in dbdata.Specifications.Where(i => i.Approve == "Yes" && i.Awailable_BOM == "Yes")
join ord in dbdata.Orders on sp.O_id equals ord.O_id
join prd in dbdata.Products.Where(k => k.Hours_prd == null) on ord.O_id equals prd.O_ID
select new { ord.Special, sp.Due_date, ord.O_id } into x
group x by x.O_id into g
select new { g.Key, X = g.OrderBy(i => i.Special).ThenBy(i => i.Due_date).First()) } into y
orderby y.X.Special, y.X.Due_date
select y.Key;
Comments:
select only fields you are interested in into x
group those fields by field you want to be distinct into group g
from each group select key (ord.O_id) and group item X, which will define order of id in result (in this case First occurrence of id will be returned)
order results by X
select Key (ord.O_id)

Related

Using Linq Join within the Where clause of another Linq Query

I want to have Linq Query as below, but the not able to, its giving me compile time error any help please? The error is "inference failed to call the Join" - any help please? I want to use join within where clause of other query, is that possible?
Case _case = (from x in this.Context().CaseRepository.GetAll()
where (from g in x.Violations
join a in this.Context().OneToManyRepository.GetAll().Where(a => a.ParentEntity == "Notice" && a.ChildEntity == "Violation")
on new { g.ViolationId, this.NOVId } equals new { a.ChildEntityId, a.ParentId }
where g.CaseId == x.CaseId
select g).Count() > 0
select x).FirstOrDefault();
this.TriggerMetaDataUpdate<Case>(_case);
this.TriggerMetaDataUpdate<InspectionResult>(this.InspectionResult);
I did it in the following way:
var Violations = (from v in UnitOfWork.ViolationRepository.GetAll()
join a in UnitOfWork.OneToManyRepository.GetAll().Where(a => a.ParentEntity == "Notice" && a.ChildEntity == "Violation")
on v.ViolationId equals a.ChildEntityId
join b in UnitOfWork.OneToManyRepository.GetAll().Where(a => a.ParentEntity == "Notice" && a.ChildEntity == "Case")
on a.ParentId equals b.ParentId
where b.ChildEntityId == caseId
orderby v.ViolationId
select v).ToList();

Select one of each matching results from group last record from date

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() });

Filtering the result set of a LINQ query

I have the following LINQ query that works fine:
var comps = (from c in tc.companies
join r in tc.registry
on c.Key equals r.Key
select new { FieldValue=r.FieldValue, Name=c.Name, Company=c.Company,Industry=c.Industry,Rank=c.Rank});
Now I want the query to only return those records where FieldValue equals to the value submitted from TextBox1
I have tried:
var comps = (from c in tc.companies
join r in tc.registry
on c.Key equals r.Key
where r.FieldValue==TextBox1
select new { FieldValue=r.FieldValue, Name=c.Name, Company=c.Company,Industry=c.Industry,Rank=c.Rank});
return View(comps);
and
var comps = (from c in tc.companies
join r in tc.registry
on c.Key equals r.Key
where r.FieldValue==TextBox1
select new { FieldValue=r.FieldValue, Name=c.Name, Company=c.Company,Industry=c.Industry,Rank=c.Rank});
comps=comps.Where(x => x.FieldValue== TextBox1);
return View(comps);
But neither returns any data. What am I doing wrong?
Update:
public ActionResult Index(string TextBox1)
{
if (TextBox1 != null)
{
var comps = (from c in tc.companies
join r in tc.registry
on c.Key equals r.Key
where r.FieldValue==TextBox1
select new { FieldValue=r.FieldValue, Name=c.Name, Company=c.Company,Industry=c.Industry,Rank=c.Rank});
return View(comps);
}
}
SOLVED! Answer is below! Not what I thought - reversing the table order in the query worked. Interesting pafr is that the query without a filter worked regardless of table order
The problem might be with what you think you are doing and what you actually do
You see as with most programing languages, in C# String is not value type but object, and the thing you are doing is actually comparing two adresses so to put it simply you check if the object in textBox1 is the same object you have as r.FildValue and what you really what to do is checking its contents, in C# each objeact has method Equals for comparing to other.
Try
where TextBox1.Equals(r.FieldValue)
The other think that you should check is if TextBox1 is value is correct
You can use System.Diagnostic.Debug.WriteLine("MyText" + TextBox1); to do that
Cheers :)
Hmmm, very strange. I was able to resolve the issue by switching the table order. Strangely the LINQ query worked fine when there was no filter but once filter was added - nothing. So I reversed the order of the tables and instead of
var comps = (from c in tc.companies
join r in tc.registry
on c.Key equals r.Key
where r.FieldValue==TextBox1
select new { FieldValue=r.FieldValue, Name=c.Name, Company=c.Company,Industry=c.Industry,Rank=c.Rank});
return View(comps);
used:
var comps = (from r in tc.registry
join c in tc.companies
on r.Key equals c.Key
where r.FieldValue==TextBox1
select new { FieldValue=r.FieldValue, Name=c.Name, Company=c.Company,Industry=c.Industry,Rank=c.Rank});
return View(comps);
and it worked like a charm!

Linq query to order list by occurences of foreign key in another list

I have two classes, Profile and Download. Download has the foreign key ProfileID which maps to the ID in Profile. Each row in Download represents one download for the connected profile.
I'm having trouble making a linq query that fetches a list of Profiles that is ordered in how many times it has been downloaded.
EDIT:
Here's what I have so far in the function.
IndexViewModel model = new IndexViewModel();
model.NewSubtitles = (from Profile in _ProfileRepo.GetAll()
orderby Profile.ID descending
select Profile).Take(5).ToList();
// This doesn't work:
// model.TopSubtitles = (from n in _ProfileRepo.GetAll()
// join d in _DownloadRepo.GetAll() on n.ID equals d.ProfileID into c
// group c by c.ProfileID into g
// orderby g.Count() descending
// select n).Take(5).ToList();
return View(model);
Try this :
model.NewSubtitles = (from Profile in _ProfileRepo.GetAll()
join downloads in _DownloadRepo.GetAll() on Profile.UserId equals downloads.UserId
group downloads by Profile into p
orderby p.Count() descending
select new {p.Key.UserId , p.Key.UserName , p.Count()).Take(5).ToList();
Have you tried something like :
from d in Downloads
orderby d.Profiles.Count()
...
?
Should do what you want:
model.TopSubtitles = (from p in _ProfileRepo.GetAll()
join d in _DownloadRepo.GetAll() on p.ID equals d.ProfileId
group d by p into g
orderby g.Count() descending
select g.Key).Take(5).ToList();
and for the LINQ syntax challenged:
model.TopSubtitles = _ProfileRepo.GetAll()
.Join(_DownloadRepo.GetAll(), p => p.ID, d => d.ProfileId, (p, d) => new { Profile = p, Download = d })
.GroupBy(x => x.Profile)
.OrderByDescending(g => g.Count())
.Select (g => g.Key)
.Take(5)
.ToList();

LINQ Using Max() to select a single row

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.

Categories