How to join two table from two different edmx using linq query - linq

How to join two table from two different edmx using linq query..
Is there a way to query from 2 different edmx at a time.
Thanks.

Update
As per your comment, EF wasn't able to parse a combined Expression tree across 2 different contexts.
If the total number of records in the tables is relatively small, or if you can reduce the number of records in the join to a small number of rows (say < 100 each), then you can materialize the data (e.g. .ToList() / .ToArray() / .AsEnumerable()) from both tables and use the Linq join as per below.
e.g. where yesterday is a DateTime selecting just a small set of data from both databases required for the join:
var reducedDataFromTable1 = context1.Table1
.Where(data => data.DateChanged > yesterday)
.ToList();
var reducedDataFromTable2 = context2.Table2
.Where(data => data.DateChanged > yesterday)
.ToList();
var joinedData = reducedDataFromTable1
.Join(reducedDataFromTable2,
t1 => t1.Id, // Join Key on table 1
t2 => t2.T1Id, // Join Key on table 2
(table1, table2) => ... // Projection
);
However, if the data required from both databases for the join is larger than could reasonably expected to be done in memory, then you'll need to investigate alternatives, such as:
Can you do the cross database join in the database? If so, look at using a Sql projection such as a view to do the join, which you can then use in your edmx.
Otherwise, you are going to need to do the join by manually iterating the 2 enumerables, something like chunking - this isn't exactly trivial. Sorting the data in both tables by the same order will help.
Original Answer
I believe you are looking for the Linq JOIN extension method
You can join any 2 IEnumerables as follows:
var joinedData = context1.Table1
.Join(context2.Table2,
t1 => t1.Id, // Join Key on table 1
t2 => t2.T1Id, // Join Key on table 2
(table1, table2) => ... // Projection
);
Where:
Join Key on table 1 e.g. the Primary Key of Table 1 or common natural
key
Join Key on table 2, e.g. a Foreign Key or common natural key
Projection : You can whatever you want from table1 and table2, e.g.
into a new anonymous class, such as new {Name = table1.Name, Data = table2.SalesQuantity}

Related

Using query hints to use a index in an inner table

I have a query which uses the view a as follows and the query is extremely slow.
select *
from a
where a.id = 1 and a.name = 'Ann';
The view a is made up another four views b,c,d,e.
select b.id, c.name, c.age, e.town
from b,c,d,e
where c.name = b.name AND c.id = d.id AND d.name = e.name;
I have created an index on the table of c named c_test and I need to use it when executing the first query.
Is this possible?
Are you really using this deprecated 1980s join syntax? You shouldn't. Use proper explicit joins (INNER JOIN in your case).
You are joining the two tables C and D on their IDs. That should mean they are 1:1 related. If not, "ID" is a misnomer, because an ID is supposed to identify a row.
Now let's look at the access route: You have the ID from table B and the name from tables B and C. We can tell from the column name that b.id is unique and Oracle guarantees this with a unique index, if the database is set up properly.
This means the DBMS will look for the B row with ID 1, find it instantly in the index, find the row instantly in the table, see the name and see whether it matches 'Ann'.
The only thing that can be slow hence is joining C, D, and E. Joining on unique IDs is extremely fast. Joining on (non-unigue?) names is only fast, if you provide indexes on the names. I'd recommend the following indexes accordingly:
create index idx_c on c (name);
create index idx_e on e (name);
To get this faster still, use covering indexes instead:
create index idx_b on b (id, name);
create index idx_c on c (name, id, age);
create index idx_d on d (id, name);
create index idx_e on e (name, town);

PL SQL - Join 2 tables and return max from right table

Trying to retrive the MAX doc in the right table.
SELECT F43.PDDOCO,
F43.PDSFXO,
F43.PDLNID,
F43.PDAREC/100 As Received,
F431.PRAREC/100,
max(F431.PRDOC)
FROM PRODDTA.F43121 F431
LEFT OUTER JOIN PRODDTA.F4311 F43
ON
F43.PDKCOO=F431.PRKCOO
AND F43.PDDOCO=F431.PRDOCO
AND F43.PDDCTO=F431.PRDCTO
AND F43.PDSFXO=F431.PRSFXO
AND F43.PDLNID=F431.PRLNID
WHERE F431.PRDOCO = 401531
and F431.PRMATC = 2
and F43.PDLNTY = 'DC'
Group by
F43.PDDOCO,
F43.PDSFXO,
F43.PDLNID,
F43.PDAREC,
F431.PRAREC/100
This query is still returning the two rows in the right table. Fairly new to SQL and struggling with the statement. Any help would be appreciated.
Without seeing your data it is difficult to tell where the problem might so I will offer a few suggestions that could help.
First, you are joining with a LEFT JOIN on the PRODDTA.F4311 but you have in the WHERE clause a filter for that table. You should move the F43.PDLNTY = 'DC' to the JOIN condition. This is causing the query to act like an INNER JOIN.
Second, you can try using a subquery to get the MAX(PRDOC) value. Then you can limit the columns that you are grouping on which could eliminate the duplicates. The query would them be similar to the following:
SELECT F43.PDDOCO,
F43.PDSFXO,
F43.PDLNID,
F43.PDAREC/100 As Received,
F431.PRAREC/100,
F431.PRDOC
FROM PRODDTA.F43121 F431
INNER JOIN
(
-- subquery to get the max
-- then group by the distinct columns
SELECT PDKCOO, max(PRDOC) MaxPRDOC
FROM PRODDTA.F43121
WHERE PRDOCO = 401531
and PRMATC = 2
GROUP BY PDKCOO
) f2
-- join the subquery result back to the PRODDTA.F43121 table
on F431.PRDOC = f2.MaxPRDOC
AND F431.PDKCOO = f2.PDKCOO
LEFT OUTER JOIN PRODDTA.F4311 F43
ON F43.PDKCOO=F431.PRKCOO
AND F43.PDDOCO=F431.PRDOCO
AND F43.PDDCTO=F431.PRDCTO
AND F43.PDSFXO=F431.PRSFXO
AND F43.PDLNID=F431.PRLNID
AND F43.PDLNTY = 'DC' -- move this filter to the join instead of the WHERE
WHERE F431.PRDOCO = 401531
and F431.PRMATC = 2
If you provide your table structures and some sample data, it will be easier to determine the issue.

linq (right) join does not return correct number of objects

I have a question about joins in LINQ. I am currently converting an access application to .NET where data is retrieved from two different databases on two different servers. In the old application the data could be retrieved by one query:
SELECT *, tbl2.Descr, tbl2.Form FROM tbl2 RIGHT JOIN tbl1 ON tbl2.proId2 = tbl1.proId
I found that one way to do this in .NET is retrieving the two tables seperatly and then joining them with LINQ. I have no experience in LINQ so I may be completely wrong with my logic or code because I can't seem to get it working.
First I tried to do a normal join (no right) but then only 18 rows are returned when the two tables contain almost 2000 rows. I also checked the data and it should definitly result in more rows, there are not that many empty cells. So then I put together a right/left join but this actually results in an error. When I debug it, everything's fine when the LINQ statement is executed but when I go into the foreach, an error is shown and the error is actually indicated in the linq statement, saying table2 is empty. When I check table1 I also see only 22 datarows.
What am I doing wrong?
DataTable dtTarget= data1.Clone();
var dt2Columns = data2.Columns.OfType<DataColumn>().Select(dc =>
new DataColumn(dc.ColumnName, dc.DataType, dc.Expression, dc.ColumnMapping));
var dt2FinalColumns = from dc in dt2Columns.AsEnumerable()
where dtTarget.Columns.Contains(dc.ColumnName) == false
select dc;
dtTarget.Columns.AddRange(dt2FinalColumns.ToArray());
var results = from table1 in data1.AsEnumerable()
join table2 in data2.AsEnumerable()
on table1.Field<String>("proId") equals table2.Field<String>("proId2")
select table1.ItemArray.Concat(table2.ItemArray).ToArray();
foreach (object[] values in results)
dtTarget.Rows.Add(values);
Outer Join:
var results = from table1 in data1.AsEnumerable()
join table2 in data2.AsEnumerable() on table1.Field<String>("proId") equals table2.Field<String>("proId2") into t_join
from table2 in t_join.DefaultIfEmpty(null) select table1.ItemArray.Concat(table2.ItemArray).ToArray();
I notice you're using strings as the join keys. Perhaps the string comparison is different between the environments (access vs .net). Access may use a case-insensitive compare, while .net's default is case-sensitive.
To make .net use a case-insensitive compare, here's the first query:
var results = data1.AsEnumerable()
.Join(
data2.AsEnumerable(),
row1 => row1.Field<String>("proId"),
row2 => row2.Field<String>("proId2"),
(row1, row2) => row1.ItemArray.Concat(row2.ItemArray).ToArray(),
StringComparer.InvariantCultureIgnoreCase); //and now caps are ignored.
and second query:
var results = data1.AsEnumerable()
.GroupJoin(
data2.AsEnumerable(),
row1 => row1.Field<String>("proId"),
row2 => row2.Field<String>("proId2"),
(row1, row2s) => new {Row1 = row1, Row2s = row2s},
StringComparer.InvariantCultureIgnoreCase)
.SelectMany(
x => x.row2s.DefaultIfEmpty(null)),
(x, row2) => row2 == null ? x.Row1.ItemArray : x.Row1.ItemArray.Concat(row2.ItemArray).ToArray()
);

Writing a LINQ query to traverse many tables

I wanted to write a LINQ query based on the SQL below.
Basically this strategy seems really confusing - why start from MerchantGroupMerchant and do 2 'from' statements?
Problem: Is there a simpler way to write this LINQ query?
var listOfCampaignsMerchantIsInvolvedIn =
(from merchantgroupactivity in uow.MerchantGroupActivities
from merchantgroupmerchant in uow.MerchantGroupMerchants
where merchantgroupmerchant.MerchantU.Id == merchantUIDGuid
select new
{
merchantgroupactivity.ActivityU.CampaignU.Id
}).Distinct();
Here is the table structure:
and the SQL:
SELECT DISTINCT Campaign.ID
FROM Campaign
INNER JOIN Activity
ON ( Campaign.CampaignUID = Activity.CampaignUID )
INNER JOIN MerchantGroupActivity
ON ( Activity.ActivityUID = MerchantGroupActivity.ActivityUID )
INNER JOIN MerchantGroup
ON ( MerchantGroup.MerchantGroupUID = MerchantGroupActivity.MerchantGroupUID )
INNER JOIN MerchantGroupMerchant
ON ( MerchantGroupMerchant.MerchantGroupUID = MerchantGroup.MerchantGroupUID )
INNER JOIN Merchant
ON ( Merchant.MerchantUID = MerchantGroupMerchant.MerchantUID )
WHERE Merchant.ID = 'M1'
No, not really, even if you use views to partially or completely reduce query size your execution plan will still look the same in the end (and execute just as fast/slow). If you have to traverse 5 joins then you have to traverse 5 joins, the only cure is "shorting" the model by introducing links between say merchant and activity or merchant and campaign. You can accomplish this by either introducing the M2M table between them (at the cost of manual maintenance), but I would not recommend it unless retrieval is really an issue. If this query is too slow you should check for existence of indexes on all join FK fields.

Entity Framework 4 generated queries are joining full tables

I have two entities: Master and Details.
When I query them, the resulting query to database is:
SELECT [Extent2]."needed columns listed here", [Extent1]."needed columns listed here"
FROM (SELECT * [Details]."all columns listed here"...
FROM [dbo].[Details] AS [Details]) AS [Extent1]
LEFT OUTER JOIN [dbo].[Master] AS [Extent2] ON [Extent1].[key] = [Extent2].[key]
WHERE [Extent1].[filterColumn] = #p__linq__0
My question is: why not the filter is in the inner query? How can I get this query? I've tried a lot of EF and Linq expressions.
What I need is something like:
SELECT <anything needed>
FROM Master LEFT JOIN Details ON Master.key = Details.Key
WHERE filterColumn = #param
I'm having a full sequential scan in both tables, and in my production environment, I have milions of rows in each table.
Thanks a lot !!
Sometimes The entity Framework does not produce the best query. You can do a few of the following to optimize.
Modify the linq statement (test with
LINQPad)
Create a stored proc and map the stored proc to return an entity
Create a view that handles the join and map the view to a new
entity

Resources