I am able to use the strongly typed LINQ Extension : .Include
result = (from A in context.Transactions.Include(_ => _.TransactionDetails)
where A.TransactionId == transactionId
select A).SingleOrDefault();
However I cannot go further within TransactionDetails. My TransactionDetails also have a navigation named User however I don't know how to put it. The available options I have inside TransactiomDetails are the regular extensions for Collections (e.g First ; FirstOrDefault,etc).
I was able to do it using the regular string method (That I want to avoid) :
result = (from A in context.Transactions.Include(_ => _.TransactionDetails)
.Include("TransactionDetails.User")
where A.TransactionId == transactionId
select A).SingleOrDefault();
Thanks
Use this:
result = context.Transactions
.Where(t => t.TransactionId == transactionId)
.Include(t => t.TransactionDetails.Select(u => u.User))
.FirstOrDefault();
Related
I am trying to generate a List<Object> using Where clause with properties from a different List<Object>. I know that I could use a .Include(), similar to a SQL join if I were using Entity Framework but I am not using Entity Framework so I don't think it would work. I have:
List<Problem> problems = MethodToCallDbAndGenerateList(); //ado.net
problems = problems.Where(x => x.Property1 == "value").ToList();
//remaining logic
List<Solved> solved = MethodToCallDb()
.Where(x => x.SolvedId == problems.ProblemId)
.ToList();
//error happens in Where(...problems.ProblemId);
//List<Problem> does not contain a definition for ProblemId
The error says the List<Problem> does not contain ProblemId but I do have that property in my class. So I am unsure of why I am getting that error.
How can I generate my List<Solved> based on filtered results from
.Where(x => x.SolvedId == problems.SolvedId);
Using LINQ to Objects, you can use the Enumerable.Join method to create a join between two List<T>s and just return the matching members:
List<Problem> problems = MethodToCallDbAndGenerateList()
.Where(x => x.Property1 == "value")
.ToList();
List<Solved> solved = MethodToCallDb()
.Join(problems, s => s.SolvedId, p => p.ProblemId, (s,p) => s)
.ToList();
However, if there are a lot of problems and solved, or if you frequently check the same list of problems, or if you are only creating problems to use in the join, you'd be better off creating a HashSet:
var problemIDs = problems.Select(p => p.ProblemId).ToHashSet();
List<Solved> solved = MethodToCallDb()
.Where(s => problemIDs.Contains(s.SolvedId))
.ToList();
NOTE: If you are only creating problems to use in the join, better to skip creating the List<Problem> and just do:
var problemIDs = MethodToCallDbAndGenerateList()
.Where(x => x.Property1 == "value")
.Select(p => p.ProblemId)
.ToHashSet();
I'm currently battling a linq query for my application using Entity Framework (6.1.3)
The query is as follows:
var productPeriods = (from pp in ctx.ProductPeriods
where pp.IsActive && pp.Product.IsBuyBackForProduct == null && !pp.Product.ProductAddOns.Any() && pp.PowerRegionID == powerRegionId
select new
{
ProductPeriod = pp,
Price = pp.Prices
.OrderByDescending(x => x.Created)
.GroupBy(x => x.FirmID)
.Select(pr => pr.FirstOrDefault())
.OrderByDescending(x => x.ProductPrice)
.FirstOrDefault()
}).ToList();
The purpose of the query is to find the latest price from the prices collection of a product period, grouped by the firm ID and then select the best price of the latest prices from each firm.
This works perfectly in Linqpad, but the first OrderByDescending(x => x.Created) doesn't work when used in context of Entity Framework.
Does anyone knows why? And perhaps have a solution for it? :-)
Thanks in advance!
Update
Thanks for all replies. I've tried the following:
select new {
ProductPeriod = p,
Price = p.Prices.GroupBy(x => x.FirmID).Select(pr => pr.OrderByDescending(x => x.Created).ThenByDescending(x => x.ProductPrice).FirstOrDefault())
}
But it seems like ThenByDescending(x => x.ProductPrice) gets ignored as well. The prices are not sorted correctly in the output. They're output like this:
Price: 0,22940, Created: 06-03-2015 10:15:09,
Price: 0,23150, Created: 06-03-2015 10:05:48
Price: 0,20040, Created: 06-03-2015 09:24:24
Update 2 (solution for now)
I came to the solution that the initial query just returns the latest prices from each firm. There's currently three firms, so the performance should be alright.
Later in my code, where I'm actually using the latest and best price, I simply do an .OrderByDescending(x => x.ProductPrice).FirstOrDefault() and check if it's not null.
I.e:
var productPeriods = (from pp in ctx.ProductPeriods
where pp.IsActive && pp.Product.IsBuyBackForProduct == null && !pp.Product.ProductAddOns.Any() && pp.PowerRegionID == powerRegionId
select new
{
ProductPeriod = pp,
Prices = pp.Prices.GroupBy(x => x.FirmID).Select(pr => pr.OrderByDescending(x => x.Created).FirstOrDefault())
}).ToList();
Later in my code:
var bestPriceOfToday = period.Prices.OrderByDescending(x => x.ProductPrice).FirstOrDefault()
The problem is the commands you are using. OrderBy and OrderByDescending do NOT add additional order by statements to the resulting query but instead they CREATE the order by statement and eliminate all orderby statements that existed before.
In order to use multiple orderby's you need to do the following:
OrderBy or OrderByDescending
ThenBy or ThenByDescending
the ThenBy statements can be used 1 or more times they just add additional order statements to the resulting query.
According to yours update, omnit select and type:
select new {
ProductPeriod = p,
Price = p.Prices.GroupBy(x => x.FirmID)
.OrderByDescending(x =>x.Created).ThenByDescending(x=>x.ProductPrice).FirstOrDefault()
}
That select was useless and could be the cause of problem
I am new to both odata and c# and I cannot figure out how to translate URI query like the following:
http://services.odata.org/Northwind/Northwind.svc/Customers(10)/Orders?$expand=Order_Details
in c#, using the linq method syntax.
I tried this way:
var customer = context.Customers.Where( x => x.Id == 10 ).First();
foreach(var order in customer.Orders.Expand("Order_Details")){
//stuff
}
But customer.Orders does not have the "Expand" method.
How do I deal with these queries where I have to expand a navigation property connected to a specific entity?
First of all your code cannot compile. x => c.Id == 10 is wrong; also there is a closing paranthesis on your foreach missing.
Second, you need to include Orders in your customer variable to do this.
I am using this Northwind v3 service to demonstrate this (http://services.odata.org/V3/Northwind/Northwind.svc/) as well as LinqPad (www.linqpad.net)
var customer = Customers.Expand("Orders/Order_Details")
.Where(cus => cus.CustomerID == "ALFKI");
foreach (var element in customer)
{
element.Orders.Dump();
}
This results in an URL call like this one:
http://services.odata.org/V3/Northwind/Northwind.svc/Customers('ALFKI')?$expand=Orders/Order_Details
Output:
Larger Image
//EDIT
Based on the comments below. If you do not want to go over the customer table and expand orders AND order_details, you can do it like this as well:
var orders = Orders.Expand("Order_Details")
.Where(o => o.CustomerID == "ALFKI").Dump();
OR
var orders = Orders.Expand(ex => ex.Order_Details)
.Where(o => o.CustomerID == "ALFKI").Dump();
You will have to request for all the child properties you need as part of the OData query itself.
try following
context.Customers.Expand("Orders/Order_Details").Where(c => x => c.Id == 10 ).First();
foreach(var order in customer.Orders){
//stuff
}
I have a LINQ, it works fine. My question is: how to convert it to Lambda Expression?
var searchResults = from study in dataContext.Studies
join location in dataContext.Locations
on study.LocationID equals location.LocationID
join doctorLocation in dataContext.DoctorLocations
on location.LocationID equals doctorLocation.LocationID
join doctor in dataContext.Doctors
on doctorLocation.DoctorID equals doctor.DoctorID
where doctor.DoctorID == doctorId
select study;
I think LINQ is more natural to me (similar to SQL script). However, in this case, I just want to convert it to Lambda Expression, but I could not make it work.
I got stuck at:
var searchResults = dataContext.Studies.Where(x =>
x.Location.DoctorLocations.FirstOrDefault() != null &&
x.Location.DoctorLocations.FirstOrDefault().DoctorID == doctorId);
This only works for FirstOrDefault. Since there are multiple DoctorLocations, I do not how to write this one.
Try this:
var searchResults = dataContext.Studies.Where(x =>
x.Location != null
&& x.Location.DoctorLocations.Any(dl => dl.DoctorID == doctorId));
you will get all Studies related to at least one DoctorLocation with DoctorID equals doctorId
var searchResults = dataContext.Studies
.Include(x => x.Locations)
.Include(x => x.DoctorLocations)
.Include(x => x.Doctors)
.Where(x => x.[InheritedPathToDoctor].DoctorId == id)
.Select(x => x.[InheritedPathToStudy].Study)
.FirstOrDefault() OR .ToList()
I have made a lot of assumptions here as to how you have set up your context. I've assumed it's a relational database and therefore the includes simply means it returns all data. I haven't tested it though so there are probably a few errors.
You require an include for every class and the where is pretty self explanatory.
I have this expression, which generates single query to the database:
db = new MyDataContext();
var productInCity = db.Products
.Where(n => n.id == 2)
.Select(k => new ProductInCityDto()
{
ProductName = k.ProductName,
CityName = k.Store.City.Name,
CountryName = k.Store.City.Country.Name
.
.
.
})
.FirstOrDefault();
I want to make this code cleaner, by putting the mapping in a function, extension method or in the object's constructor, something like this:
db = new MyDataContext();
var productInCity = db.Products
.Where(n => n.id == 2)
.Select(k => new ProductInCityDto(k))
.FirstOrDefault();
But, in this case, multiple queries to the DB are generated (I use LinqToSql Profiler).
Is there a way to isolate the mapping (Select statement) in order to achieve better code readability?
YES, if you look at the actual signature of the Select extension method on IQueryable you will find that it does not take a function but an Expression>.
So, just do that...
Expression<Func<Product, ProductInCityDto>> MyMappingExpression
{
get
{
return product => new ProductInCityDto
{
...
}
}
}
and then
db = new MyDataContext();
var productInCity = db.Products.Where(n => n.id == 2)
.Select(MyMappingExpression)
.FirstOrDefault();
If you need to use MyMappingExpression in process you will likely want to convert it to a
Func<Product, ProductInCityDto>
by calling the Expression.Compile() method.
Instead of creating mappings by hand, you may use AutoMapper. But if you do not want to create the mapping using a third party tool just change the query to the following;
var productInCity = new ProductInCity(
db.Products.Include("Store").SingleOrDefault(n => n.id == 2));