Let's say I need to make a complicated query to database (it includes 4 tables). I've written 4 different methods that query 4 different tables and I know it's not good:
var groups = *method that contains of .Where(), .Select() etc, that queries groups*
var marks = *method that has a parameter GROUPS and queries another table*
...
So it's like a ladder: to query another table, I need the results of the previous query (that has another context :))
I know about the Join method, but how can I give it the results of previous query?
Thank you in advance
I'm not sure if I understand the question correctly, but when it comes to joining multiple tables in one query, you can use model relationships (you can create them yourself or with the scaffold command, here you have how to use it ), then you will be able to use a relation in a linq query.
Related
I have something like this in my C# MVC controller:
from table1 in db.Table1.AsQueryable()
join table2 in db.Table2.AsQueryable() on table1.Col1 equals table2.Col1
join table3 in db.table3.AsQueryable() on new { table2.Col2, table2.Col5 } equals new { table3.Col2, table3.Col5 }
.
.
few more joins
.
.
WHERE ......
select new {table1.Prop1, table2.Prop2, table3.Prop3}
When I watch what it runs on SQL profiler, I was expecting a single query with all the joins. What it does instead, it selects all columns from all tables in separate queries. i.e. Runs
SELECT * FROM Table2 --Instead of * it has all column names
when that's finished running, it runs
SELECT * FROM Table3 --Instead of * it has all column names
and so on for each table. Tables are big so it takes too long, using a lot of memory. I added AsQueryable() on the entities but it didn't make a difference, still multiple queries. db is a DbContext, using core 2.
How can I change the LINQ or some other setting so the whole thing runs as a single query?
Update
It looks like the problem was caused by having Convert.ToInt32( on one of the join columns. The int column I was joining on is nullable in one table and non-nullable in the other table, I had Convert.ToInt32( on the nullable
table, removing the convert generated a single query.
According to LINQ2SQL documents:
When you query for an object, you actually retrieve only the object you requested. The related objects are not automatically fetched at the same time.
The DataLoadOptions class provides two methods to achieve immediate loading of specified related data. The LoadWith method allows for immediate loading of data related to the main target. The AssociateWith method allows for filtering related objects.
This is an issue with Lazy Loading vs Eager Loading.
This is a great post with very good explanation.
Lazy Loading And Eager Loading In LINQ To SQL
I'm trying to join two tables from different servers , but it keeps throwing this exception :
This method supports LINQ to Entities infrastructure and is not intended to be used directly from your code.
here is my query :
var myList = (from myTableA in _dbProvider.ContextOne.TableA
join myTableB in _dbProvider.ContextOne.TableB on myTableA.ProductId equals myTableB.Oid
join myTableC in _dbProvider.ContextTwo.TableC on myTableB.Id equals myTableC.ProductId
where
select myTableC.Name).Distinct().ToList();
what's that mean ?,
knowing that I found an other solution by getting data separately from each table into lists then joining them but it's very greedy in terms of time
is there any other solution ?
You can't join two tables from two different servers. Definitely not from EF.
Your best bet is to only fetch the data in two separate lists and then join them together using Linq to objects.
Let me make an imaginary example: You have 1000,000 invoices on one table, each one has about 10 items, a total of 10,000,000 invoice details on anther server. You need Invoices and their details for 10 first invoices created on 2015-5-4
you send a query to first DB, getting only that 10 invoices, extract their ids and use that to query about 100 rows from the other server. This is only about two times slower than making a single join query.
In some cases this becomes impossible (you have conditions on both tables) and you need to bring more rows, but in simple scenarios this is possible.
I have a database with several tables and I am using the following query to return a record that matches a string(Name).
In the MHP table there is a Name field(primary key), Num_Sites and a few more, but these are the only ones I am concerned with.
In the MHP_Parcel_Info table there are many fields with one of them being Name(foreign key). There is a parcel_id field and in some case there may only be one parcel for one name, but there may also be many parcels for a Name.
As it is now my query will return one of the rows for instances where there are multiple parcels for a name.
What I would like to do is: if there is more than one parcel for a Name, have all the parcels put into a list(so I can display in listbox on form).
My SQL skills are limited and I don’t know how I would go about doing something like this.
SELECT MHP_Parcel_Info.*, MHP.NUM_SITES FROM MHP_Parcel_Info INNER JOIN MHP ON " +
"(MHP_Parcel_Info.MHP_NAME = MHP.MHP_NAME) WHERE MHP_Parcel_Info.MHP_NAME='" + strValue + "'"
This is not something you can do directly in SQL. There's no way to select data in a parent/child structure in a SQL query - you have to do that as a post-processing step.
Since this is tagged as C# and Winforms I'm assuming this is from inside a .Net app. You will need to execute the query as you have it above, then in C# you can use the LINQ GroupBy extension method on the result to group the results into a list of IGrouping objects which use the name as the key, and has all of the parcel info as the items in the list.
Even better, if you are using (or can use) LINQ to SQL or Entity Framework you can just write a linq query that fetches the data from the database and does the grouping all at once.
I'm using Entity Framework 5, ObjectContext and POCOs on my data access layer. I have a generic respository implementation and I have a method that queries the database with paging using Skip() and Take(). Everything works fine, except that the query performance is very slow when skipping a lot of rows (I'm talking about 170k rows)
This is an excerpt of my query on Linq to Entities:
C# Code:
ObjectContext oc = TheOBJEntitiesFactory.CreateOBJEntitiesContext(connection);
var idPred = oc.CreateObjectSet<view_Trans>("view_Trans").AsQueryable();
idPred = idPred.OrderBy(sortColumn, sortDirection.ToLower().Equals("desc"));
var result = idPred.Skip(iDisplayStart).Take(iDisplayLength);
return new PagedResult<view_Trans>(result, totalRecords);
In the translated query to Transact-SQL I noticed that instead of using the ROW_NUMBER() clause with the view directly its making a sub-query and applying the ROW_NUMBER() to the results of the sub-query...
example:
select top(10) extent1.A, extent1.B.extent1.C from (
select extent1.A, extent1.B, extent1.C,
row_number() OVER (ORDER BY [Extent1].[A] DESC) AS [row_number]
from (
select A,B,C from table as extent1)) as extent1
WHERE [Extent1].[row_number] > 176610
ORDER BY [Extent1].[A] DESC
This takes about 165 seconds to complete. Any idea on how to improve the performance of the translated query statement?
For those not following the comments above, I suspected the problem was not the extra SELECT, since that extra SELECT is present on many, many EF queries which do not take 165s to run. I eventually noticed that his ObjectSet referenced a VIEW and wondered if that might be part of the problem. After some experimentation, he narrowed the problem down to a LEFT JOIN inside the view. I suggested that he ran the Database Tuning Advisor on that query; he did, and the two indices suggested fixed the problem.
One reason for the slowness is probably that your sql is ordering your rows twice.
To control the query, the only option I know of is to call idPred.SqlQuery("Select ...", params). This will allow you to write your own optimized query for the data request.
My application is based on Entity Framework. I am offering users to query a particular table by saving their queries in another table. For example, TopQuery table in database stores all the queries which are popular among users.
These queries are performed on table "TableData"
For test purposed, I have tried the following and it works. The only problem is that it returns all columns where as I would like to use columns that are mentioned by users in their queries.
string queryString =
#"SELECT VALUE table FROM TestEntities.TableData AS table where table.col1 = 'test'";
ObjectQuery<TableData> productQuery2 =
new ObjectQuery<TableData>(queryString, context);
My problem is that if user stores a query in database like this, it doesn't work.
SELECT table.col1, table.col2, table.col3 FROM TestEntities.TableData AS table where table.col1 = "test"
I get the exception: The specified cast from a materialized System.Data.Objects.MaterializedDataRecord' to'TestEntities.TableData'type is not valid.
I have also tried this without any luck.
"SELECT it.col1, it.col2 FROM TableData WHERE it.col1 = 'test'"
What should I do in such case?
Regards,
You will never get ObjectQuery<TableData> once you try to select only subset of columns. Using ObjectQuery<TableData> works only when you select whole entity as your first query did - that is a strongly typed approach enforced by Entity framework.
ESQL doesn't support projection in the way Linq-to-entities does (by allowing you to project to a new anonymous or non mapped type). When using projection with ESQL you must work with ObjectQuery<DbDataRecord>.