How to efficiently select child objects through LINQ - c#

In an effort to access child objects only through their aggregate roots, I am struggling to think of efficient ways to select the correct data. Could I rewrite the following to be more efficient/concise?
var jobReport = db.Jobs
.Where(j => j.JobReports.Any(jr => jr.ReportId == reportId))
.Select(j => j.JobReports.Single(jr => jr.ReportId == reportId))
.Single();

What you wrote would be equivalent to:
var jobReport = db.Jobs.SelectMany(j => j.JobReports)
.Single(jr => jr.ReportId == reportId);

Related

Using OR condition in LINQ C#

I do write the following SQL query in LINQ c#
SELECT max(creation_date) from TRS where approval_status='APPROVED' and transaction_type in ('Sale','PRE')
I tried building below query on a list as follows
var session = txns.Where(a => a.transaction_type.Equals("SALE"))
.Where(a => a.transaction_type.Equals("PRE"))
.Where(a => a.approval_status.Equals("APPROVED"))
.OrderByDescending(a => a.creation_date).Select(a => a.creation_date).FirstOrDefault();
The above query didnt work as I wasn't sure of how to use Max and OR condition in LINQ c#
May I know a better solution?
var session = txns
.Where(a => a.transaction_type.Equals("SALE") || a.transaction_type.Equals("PRE"))
.Where(a => a.approval_status.Equals("APPROVED"))
.Select(a=>a.creation_date).Max();
or
var txtypes=new[]{"SALE","PRE"};
var session = txns
.Where(a => txtypes.Contains(a.transaction_type))
.Where(a => a.approval_status.Equals("APPROVED"))
.Select(a=>a.creation_date).Max();
or
var session = txns
.Where(a => a.transaction_type.Equals("SALE") || a.transaction_type.Equals("PRE"))
.Where(a => a.approval_status.Equals("APPROVED"))
.Max(a=>a.creation_date);
You can use || operator to combine your two conditions or you can use Contains which would generate a query like SELECT IN (....)
var transcationTypes = new[] {"SALE", "PRE"};
var sessions = txns.Where(a => transcationTypes.Contains(a.transaction_type)
&& a.approval_status == "APPROVED")
.Select(a => a.creation_date)
.Max();
Once you have filtered out the results you can use Max to select the maximum value.

LinQ method syntax multiple tables with .where() and without joins

How do fetch data from multiple tables with method syntax without using joins, but only .where() methods?
I'm making a select against EF5 db context which maps to this legacy table structure where I have a persons detail table and another table which refers both to itself to create a hierarchy and to the person details table this way:
PersonSet
.Where(p => p.LastName.ToLower()=="surname")
.Join(SubsetSet, p => p.Id, ss => ss.SubsetLink, (p, ss) => new { PersonDetail = p, person = ss })
.Where(m => m.person.Frame=="a" && m.person.Purpose=="1")
.Join(SubsetSet, ss1 => ss1.person.Owner, person => person.SubsetLink, (ss1, ss2) => new { person = ss1, club = ss2 })
.Where(a => a.club.Frame=="b" && a.club.Purpose=="2")
.Join(SubsetSet, ss => ss.club.Owner, ss2 => ss2.SubsetLink, (ss, ss2) => new { club = ss, association = ss2 })
.Where(a => a.association.Frame=="b" && a.association.Purpose=="3")
.Join(SubsetSet, ss => ss.association.Owner, ss3 => ss3.SubsetLink, (ss, ss3) => new { association = ss, district = ss3})
.Where(d => d.district.Frame=="b" && d.district.Purpose=="4" && d.district.SubsetLink=="12345")
.Select(proj => new { proj.association.club.person, proj.association.club, proj.association, proj.district })
.OrderByDescending(a => a.association.club.person.phyperson.FirstName)
.Take(10).Dump();
The above query works at least in LinqPad but, it seems to me that If I could get rid of those joins the statement might look a bit nicer. Now I know, like in the Albahari example below, that this can be done with query syntax. But I couldn't find an example that would illustrate this situation with method syntax. The way I'm trying to approach this might of course be wrong and that's why I can't find suitable examples.
Here I found something similar, but couldn't make it work in LinQPad:
Is multiple .Where() statements in LINQ a performance issue?
Or this one, where the solution is again in query syntax:
Cross Join with Where clause
Or this example by Albahari: (http://www.linqpad.net/WhyLINQBeatsSQL.aspx)
from p in db.Purchases
where p.Customer.Address.State == "WA" || p.Customer == null
where p.PurchaseItems.Sum (pi => pi.SaleAmount) > 1000
select p
Consider this query:
var q = from order in orders
from orderline in order.Lines
where orderline.Count > 10
select order.Discount * orderline.Price;
this more or less corresponds to
var q = orders
.SelectMany(order => order.Lines, (order, orderline) => new { order, orderline})
.Where(item => item.orderline.Count > 10)
.Select(item => item.order.Discount * item.orderline.Price);
For more information on SelectMany, see the MSDN documentation.
If you don't have associations defined:
var q = from order in orders
from orderline in orderLines
where orderline.OrderId == order.Id
where orderline.Count > 10
select order.Discount * orderline.Price;
this more or less corresponds to
var q = orders
.SelectMany(order => orderLines, (order, orderline) => new { order, orderline})
.Where(item => item.orderline.OrderId == item.order.Id)
.Where(item => item.orderline.Count > 10)
.Select(item => item.order.Discount * item.orderline.Price);

LINQ to SQL querying across relationships

This is driving me mad. I thought it seemed simple enough but the below is returning a list of IEnumerable containing the entities I need, instead of just a list of entities:
db.tblPeople.Where(p => p.id == id).Select(s => s.tblCars.Select(z => z.tblCarType)).ToList();
My attempt is to retrieve a list of all carType entities associated with the personId.
I assume it's something to do with the last nested select?
Do like this because you are expecting multiple records to be returned:
var result = db.tblPeople
.Where(p => p.id == id)
.Select(s => s.tblCars
.SelectMany(z => z.tblCarType)).ToList();
Use SelectMany in order to flatten IEnumerable<IEnumerable<CarType>> into IEnumerable<CarType>.
var carTypes =
db.tblPeople
.Where(p => p.id == id)
.SelectMany(s =>
s.tblCars
.Select(z => z.tblCarType))
.ToList();
This translates from
var carTypes =
(from person in tblPeople
from car in person.tblCar
from carType in car.tblCarType
where person.id == id
select carType).ToList();
This is what you want/need:
db.tblPeople.Where(p => p.id == id).SelectMany(s => s.tblCars.Select(z => z.tblCarType)).ToList();

LINQ Grouping by ParentId

I have a seemingly simple task that I am having far more trouble than I care to admit doing. I have a hierarchical table that I need to query and display the results grouped by the parent with associated children.
My current LINQ query:
var quests = Questions.Include(q => q.Question2)
.Include(q => q.Sections)
.Include(q => q.QuestionType)
.Include(q => q.AnswerOptions)
.Where(sq => sq.Sections.Any(s => s.SectionId == sectionId))
.OrderBy(q=> q.QuestionId).ThenBy(q => q.ParentQuestionId);
This produces a result set of:
What I want to produce is:
My Question is simply, how can I get the desired results using Lambda syntax.
Update based on Servys' comment.
First line is to make sure all related questions are grouped together.
Second line is to make sure parent question is first.
Third line is to order properly
.OrderBy(q => q.ParentQuestionId == null ? q.QuestionId : q.ParentQuestionId)
.ThenBy(q => q.ParentQuestionId == null ? 0 : 1)
.ThenBy(q => q.DisplayOrder);
So it seems what you're really trying to create here is a tree based structure in which, at the top level, you have all questions with no parent, and then as "child" nodes all questions that have that as a parent.
var questions = GetAllQuestions();//here is where you can put your includes, etc.
var query = questions.Where(q => q.ParentQuestionId != null)
.GroupBy(q => q.ParentQuestionId)
.Select(group => new
{
Parent = questions.First(q => q.QuestionId == group.Key),
Children = group.OrderBy(q => q.DisplayOrder),
})
.OrderBy(group => group.Parent.DisplayOrder);
.OrderBy(x => (x.ParentQuestionId==null?x.QuestionId:x.ParentQuestionId.Value));

LINQ aggregate sequence contains no elements

I'm dynamically building up a query starting with this:
var items = db.Items;
...
case "4":
items = items.OrderBy(x => x.Ratings.Average(t => t.score)).ThenBy(x => x.title);
The problem is that some items don't have any data in the ratings table yet, so I believe it's trying to average over data that doesn't exist. Using DefaultOrEmpty() at the end doesn't seem to have any effect. Any suggestions on how I would fix this?
If you are using this form:
var effectiveFloor =
policies
.Where(p => p.PricingStrategy == PricingStrategy.EstablishFloor)
.Max(p => p.Amount);
Then the solution is:
var effectiveFloor =
policies
.Where(p => p.PricingStrategy == PricingStrategy.EstablishFloor)
.DefaultIfEmpty()
.Max(p => p==null ? 0 : p.Amount);
Found here
items = items.Where(x=>x.Ratings.Any()).
OrderBy(x => x.Ratings.Average(t => t.score)).
ThenBy(x => x.title);
Try that.

Categories