I'm using the entity framework and linq to do multiple left outer joins but it takes 3 seconds to run the query through the entity framework.
I used ((System.Data.Objects.ObjectQuery)query).ToTraceString(); and tested the sql statement in management studio and it executed instantly.
Here is the linq code.
var query = from Inventory in db.INVENTORies
join NewInventory in db.NEW_INVENTORY on Inventory.Barcode equals NewInventory.Barcode into lj_1
from q_NewInventory in lj_1.DefaultIfEmpty()
join Categories in db.Categorys on Inventory.CAT_ID equals Categories.CAT_ID into lj_2
from q_Categories in lj_2.DefaultIfEmpty()
join SCategories in db.StoneCategories on Inventory.TP_ID equals SCategories.TP_ID into lj_3
from q_SubCategory in lj_3.DefaultIfEmpty()
join qSupplier in db.Suppliers on Inventory.SUP_ID equals qSupplier.SUP_ID into lj_4
from q_Supplier in lj_4.DefaultIfEmpty()
join qStatus in db.Statuses on Inventory.ST_ID equals qStatus.ST_ID into lj_5
from q_Status in lj_5.DefaultIfEmpty()
join q_Locations in db.Locations on Inventory.LOC_ID equals q_Locations.LOC_ID into lj_7
from q_locations in lj_7.DefaultIfEmpty()
join q_Stone1 in db.Stones on Inventory.StoneID_1 equals q_Stone1.STONE_ID into lj_s1
from q_stone1 in lj_s1.DefaultIfEmpty()
join q_Stone2 in db.Stones on Inventory.StoneID_2 equals q_Stone2.STONE_ID into lj_s2
from q_stone2 in lj_s2.DefaultIfEmpty()
join q_Stone3 in db.Stones on Inventory.StoneID_3 equals q_Stone3.STONE_ID into lj_s3
from q_stone3 in lj_s3.DefaultIfEmpty()
join q_Stone4 in db.Stones on Inventory.StoneID_4 equals q_Stone4.STONE_ID into lj_s4
from q_stone4 in lj_s4.DefaultIfEmpty()
join q_Stone5 in db.Stones on Inventory.StoneID_5 equals q_Stone5.STONE_ID into lj_s5
from q_stone5 in lj_s5.DefaultIfEmpty()
join q_Stone6 in db.Stones on Inventory.StoneID_6 equals q_Stone6.STONE_ID into lj_s6
from q_stone6 in lj_s6.DefaultIfEmpty()
join q_Stone7 in db.Stones on Inventory.StoneID_7 equals q_Stone7.STONE_ID into lj_s7
from q_stone7 in lj_s7.DefaultIfEmpty()
join q_Stone8 in db.Stones on Inventory.StoneID_8 equals q_Stone8.STONE_ID into lj_s8
from q_stone8 in lj_s8.DefaultIfEmpty()
join qMasterInventory in db.MASTERINVENTORies on q_NewInventory.InvItemNo equals qMasterInventory.INVITEMNO into lj_6
from q_MasterInventory in lj_6.DefaultIfEmpty()
where Inventory.Barcode == _Barcode
select new
{
inv_InvID = Inventory.INV_ID, inv_Barcode = Inventory.Barcode,
inv_catID = Inventory.CAT_ID, inv_SubCatID = Inventory.TP_ID, inv_Price = Inventory.ITEM_PRICE, inv_Cost = Inventory.ITEM_COST,
inv_PricePoint = Inventory.PricePoint, inv_StatusID = Inventory.ST_ID, inv_StID = Inventory.ST_ID, inv_SupID = Inventory.SUP_ID,
inv_LocID = Inventory.LOC_ID, inv_LabSupplier = Inventory.LabSupplier, inv_LabStone1 = Inventory.LabStone1, inv_LabCategory = Inventory.LabCategory,
inv_LabExtra = Inventory.LabExtra, inv_LabMadeIn = Inventory.LabMadeIn, inv_Width = Inventory.ChainThickNess, inv_Size = Inventory.ChainSize,
inv_Stone1 = Inventory.StoneID_1,inv_Stone2 = Inventory.StoneID_2,inv_Stone3 = Inventory.StoneID_3,inv_Stone4 = Inventory.StoneID_4,inv_Stone5 = Inventory.StoneID_5,inv_Stone6 = Inventory.StoneID_6,inv_Stone7 = Inventory.StoneID_7,inv_Stone8 = Inventory.StoneID_8,inv_Stone9 = Inventory.StoneID_9,inv_Stone10 = Inventory.StoneID_10,
stat_Status = q_Status.DESCRIPTION,
cat_Category = q_Categories.DESCRIPTION,
subCat_SubCategory = q_SubCategory.DESCRIPTION,
sup_Supplier = q_Supplier.Name,
loc_Location = q_locations.DESCRIPTION,
mas_SKU = q_MasterInventory.INVITEMNO,
mas_GUID = q_MasterInventory.ItemGUID,
stone1 = q_stone1.DESCRIPTION,
stone2 = q_stone2.DESCRIPTION,
stone3 = q_stone3.DESCRIPTION,
stone4 = q_stone4.DESCRIPTION,
stone5 = q_stone5.DESCRIPTION,
stone6 = q_stone6.DESCRIPTION,
stone7 = q_stone7.DESCRIPTION,
stone8 = q_stone8.DESCRIPTION,
};
Create database view for this query and map the view to new read only entity. After that compare differences between pure LINQ execution and a new execution. If the problem was with converting your terrible LINQ query to SQL you will avoid it by using this approach. If it is still slow the problem will be elsewhere.
Guys in comments said that you have to re-write it in T-SQL. True. You can try one of SQL to LINQ converter tools.
Also use MS SQL Profiler to see what happens and improve TSQL performance.
Try to add indexes but not too much :)
Related
I am using this example Linq code:
from objpath in _context.PathModel
join objOriginalStation in _context.StationModel
on objpath.IdStazioneOrigine equals objOriginalStation.IDStazione
join objDesttinationStation in _context.StationModel
on objpath.IdStazioneDestinazione equals objDesttinationStation.IDStazione
join objVia1Station in _context.StationModel
on objpath.IdVia1 equals objVia1Station.IDStazione
join objVia2Station in _context.StationModel
on objpath.IdVia2 equals objVia2Station.IDStazione
select new NewPercorsiModel
{
IdPercorso = objpath.IdPercorso,
IdSottorete = objpath.IdSottorete,
Distanza = objpath.Distanza,
IdStazioneDestinazione = objpath.IdStazioneDestinazione,
IdStazioneOrigine = objpath.IdStazioneDestinazione,
IdVia1 = objpath.IdVia1,
IdVia2 = objpath.IdVia2,
Versione = objpath.Versione ?? string.Empty,
StazioneOrigineName = objOriginalStation.NomeStazione,
StazioneDestinazioneName = objDesttinationStation.NomeStazione,
Via1Name = objVia1Station.NomeStazione,
Via2Name = objVia2Station.NomeStazione ?? string.Empty
};
First of all my question is that, have I a better solution to improve my code?
and second and important my question is that how could I check nullable for my objects(for example for objVia2Station) because when they are null I don't have all my records but I don't have any error also.
you can use "DefaultIfEmpty()" after each join like this code
from objpath in _context.PathModel
join objOriginalStation in _context.StationModel
on objpath.IdStazioneOrigine equals objOriginalStation.IDStazione into object1
from Ob1 in object1.DefaultIfEmpty()
join objDesttinationStation in _context.StationModel
on objpath.IdStazioneDestinazione equals objDesttinationStation.IDStazione into object2
from Ob2 in object2.DefaultIfEmpty()
join objVia1Station in _context.StationModel
on objpath.IdVia1 equals objVia1Station.IDStazione into object3
from Ob3 in object3.DefaultIfEmpty()
join objVia2Station in _context.StationModel
on objpath.IdVia2 equals objVia2Station.IDStazione into object4
from Ob4 in object4.DefaultIfEmpty()
select new NewPercorsiModel
{
IdPercorso = objpath.IdPercorso,
IdSottorete = objpath.IdSottorete,
Distanza = objpath.Distanza,
IdStazioneDestinazione = objpath.IdStazioneDestinazione,
IdStazioneOrigine = objpath.IdStazioneDestinazione,
IdVia1 = objpath.IdVia1,
IdVia2 = objpath.IdVia2,
Versione = Ob1.Versione ,
StazioneOrigineName = objOriginalStation.NomeStazione,
StazioneDestinazioneName = objDesttinationStation.NomeStazione,
Via1Name = objVia1Station.NomeStazione,
Via2Name = Ob4.NomeStazione
};
this code in equal to "Left Outer Join", But I don't like it because we can use Inheritance Strategy in Entity Framework
You should start receiving data when you encounter another table. like this:
var query = context.BaseTable.Select(x => new
{
x.Id,
x.field1,
x.field2,
..
..
alias_name= x.ForeignTable== null ? "" : x.ForeignTable.Name
});
This question already has answers here:
Linq-to-Entities Join vs GroupJoin
(3 answers)
Closed 7 years ago.
I am new to linq... and I am wondering if I am doing it right..
Here's my code...
var result = from a in ctx.ItemReceipts
join b in ctx.ItemReceiptStatusTypes on a.Status equals b.ItemReceiptStatusTypeID
join c in ctx.PurchaseOrders on a.ReferenceID equals c.PurchaseOrderID
into leftJoinItemReceipts
from d in leftJoinItemReceipts.DefaultIfEmpty()
where a.ItemReceiptID.Equals(ItemReceiptID)
select new
{
CItemReceiptID = a.ItemReceiptID,
CTransactionNumber = a.TransactionNumber,
CRemarks = a.Remarks,
CStatus = a.Status,
CStatusType = b.Description,
CReferenceID = a.ReferenceID,
CReferenceTypeID = a.ReferenceTypeID,
CTransactionDate = a.TransactionDate,
CDateReceived = a.DateReceived,
CTotalCost = a.TotalCost,
CPONumber = d.PONumber
};
It runs perfectly... but I really can't understand the into part.. I dunno if it's really a left join but gives me the data that I want... it gives me all data in itemreceipts even though they don't have something in common with PurchaseOrder....
I need explanation... better a comparison between mysql and linq...
from a in ctx.ItemReceipts
join b in ctx.ItemReceiptStatusTypes on a.Status equals b.ItemReceiptStatusTypeID
into leftJoinItemReceipts
from d in leftJoinItemReceipts.DefaultIfEmpty()
join c in ctx.PurchaseOrders on d.ReferenceID equals c.PurchaseOrderID
This will do a left join on ItemReceipts and ItemReceiptStatusTypes and then a inner join with PurchaseOrders
My sql query is
SELECT DISTINCT
tblProjects.RevID, tblProjects.CEQRNum, tblProjects.ProjectName, GEOCODE.BBL, tblProjects.BoroID, GEOCODE.BLOCK, GEOCODE.LOT,
tblMilestoneType.MilestoneName, tblMilestone.MilestoneDate
FROM tblMilestoneType INNER JOIN
tblMilestone ON tblMilestoneType.MilestoneID = tblMilestone.MilestoneTypeID RIGHT OUTER JOIN
tblProjects ON tblMilestone.RevID = tblProjects.RevID LEFT OUTER JOIN
GEOCODE ON tblProjects.RevID = GEOCODE.RevID
WHERE (
tblMilestone.MilestoneDate IN (SELECT MAX(tblMilestone.MilestoneDate) AS MilestoneDate
FROM tblMilestone INNER JOIN tblMilestoneType ON tblMilestone.MilestoneTypeID = tblMilestoneType.MilestoneID
GROUP BY tblMilestone.RevID)
)
ORDER BY tblProjects.RevID
I am trying to convert this to linq.
So i started with
projectList = db.tblMilestoneTypes
.Join(db.tblMilestones,
mileType => mileType.MilestoneID,
mile => mile.MilestoneTypeID,
(mileType, mile) => new
{
tblMilestoneType = mileType,
tblMilestone = mile
})
.Join(db.tblProjects,
project => project. // does not work)
Also tried
projectList = from MilestoneTypeTable in db.tblMilestoneTypes
join MilestoneTable in db.tblMilestones on MilestoneTypeTable.MilestoneID equals MilestoneTable.MilestoneTypeID
rig // no right or left join.
How do i do this
Neha
You can try
projectList = from MilestoneTypeTable in db.tblMilestoneTypes
join MilestoneTable in db.tblMilestones on MilestoneTypeTable.MilestoneID equals MilestoneTable.MilestoneTypeID into MileStones
from mileStone in MileStones
join from projects in db.tblProjects
on mileStone.RevID equals projects.RevID
select new { MileStoneType = MilestoneTypeTable, MileStones = mileStone , Project = projects };
Well After a lot of R&D This is what I found out
the T-SQL with LEFT OUTER JOIN and RIGHT OUTER JOIN can be converted to one query with only LEFT OUTER JOIN
put subquery as a part of join
and here is the query.
var query = from ProjectTable in db.tblProjects
from GeoCodeTable in db.GEOCODEs.Where(geo => geo.RevID == ProjectTable.RevID).DefaultIfEmpty()
from MilestoneTable in db.tblMilestones.Where(mile => mile.RevID == GeoCodeTable.RevID && mile.MilestoneDate == db.tblMilestones.OrderBy(x => x.RevID).Select(x => x.MilestoneDate).Max()).DefaultIfEmpty()
from MilestomeTypeTable in db.tblMilestoneTypes.Where(mt => mt.MilestoneID == MilestoneTable.MilestoneTypeID).DefaultIfEmpty()
select new
{
Milestone = MilestoneTable,
Project = ProjectTable,
GeoCode = GeoCodeTable,
MilestomeType = MilestomeTypeTable
};
I have this query below. After that, I want to populate a list with the results. How should I do ?
var query = from cust in context.Customer
join city in context.Cities on cust.id_city equals city.id
join state in context.State on city.id_state equals state.id
join reg in context.Region on state.id_region equals reg.id
select new
{
nameCust = cust.name,
nameCity = city.name,
nameState = state.name,
nameRegion = reg.name
};
You should be able to call ToList() on the return value:
var queryResult = (from cust in context.Customer
join city in context.Cities on cust.id_city equals city.id
join state in context.State on city.id_state equals state.id
join reg in context.Region on state.id_region equals reg.id
select new
{
nameCust = cust.name,
nameCity = city.name,
nameState = state.name,
nameRegion = reg.name
}).ToList();
I'm wondering though, if you are using Entity Framework. If so: this might be a bether solution:
var queryResult = context.Customer
.Include(customer => customer.City)
.Include(customer => customer.State)
.Include(customer => customer.Region)
.ToList();
( ! ) Keep in mind you are loading a complete table into memory using ToList()
I have a beginners LINQ2SQL question. I have this huge (but not complex) SQL statement:
SELECT Artikel.ArtikelID,
Artikel.CategorieID,
Artikel.ImageFile,
Artikel.RetailPrijs,
ISNULL(ShopArtikel.VerkoopsPrijs, Artikel.VerkoopsPrijs) AS VerkoopsPrijs,
Artikel.ArtikelCode,
Artikel.InAssortimentSinds,
ArtikelTaal.ArtikelNaam,
ArtikelTaal.ArtikelOmschrijving
FROM Artikel
INNER JOIN ArtikelTaal ON Artikel.ArtikelID = ArtikelTaal.ArtikelID
INNER JOIN ShopArtikel ON Artikel.ArtikelID = ShopArtikel.ArtikelID
INNER JOIN Categorie ON Artikel.CategorieID = Categorie.CategorieID
INNER JOIN CategorieTaal ON Categorie.CategorieID = CategorieTaal.CategorieID
INNER JOIN Shop ON ShopArtikel.ShopId = Shop.ShopID
INNER JOIN CategorieGroepShop ON Shop.ShopID = CategorieGroepShop.ShopId
INNER JOIN Taal ON ArtikelTaal.TaalCode = Taal.TaalCode AND CategorieTaal.TaalCode = Taal.TaalCode
INNER JOIN CategorieGroepTaal ON Taal.TaalCode = CategorieGroepTaal.TaalCode AND CategorieGroepShop.CategorieGroepId = CategorieGroepTaal.CategorieGroepID
INNER JOIN CategorieGroep ON Categorie.CategorieGroepID = CategorieGroep.CategorieGroepID AND CategorieGroepTaal.CategorieGroepID = CategorieGroep.CategorieGroepID AND CategorieGroepShop.CategorieGroepId = CategorieGroep.CategorieGroepID
WHERE (Shop.ShopID = 23) AND
(Taal.TaalCode = 'dut') AND
(Artikel.Onzichtbaar = 0) AND
(Artikel.NietBestelbaar = 0) AND
(Categorie.Onzichtbaar = 0) AND
(Artikel.Voorraad >= Artikel.LevertijdDrempel)
and I am converting this to LINQ and have this:
var allProducts = from artikelen in dc.Artikels
join sa in dc.ShopArtikels on artikelen.ArtikelID equals sa.ArtikelID
join at in dc.ArtikelTaals on artikelen.ArtikelID equals at.ArtikelID
join cat in dc.Categories on artikelen.CategorieID equals cat.CategorieID
join catt in dc.CategorieTaals on cat.CategorieID equals catt.CategorieID
join catg in dc.CategorieGroeps on cat.CategorieGroepID equals catg.CategorieGroepID
join catgt in dc.CategorieGroepTaals on catg.CategorieGroepID equals catgt.CategorieGroepID
join sh in dc.Shops on sa.ShopId equals sh.ShopID
join catgs in dc.CategorieGroepShops on sh.ShopID equals catgs.ShopId
join tl in dc.Taals on new { tc1 = at.TaalCode, tc2 = catgt.TaalCode } equals new { tc1 = tl.TaalCode, tc2 = tl.TaalCode }
where sh.ShopID == shop.BLL.Business.ShopController.CurrentShop.Id
select dc.Artikels;
but I have the idea that I made some (minor) mistakes while joining.
any ideas please!
EDIT
I have rewritten the LINQ query to this:
var allProducts = from artikelen in dc.Artikels
join at in dc.ArtikelTaals on artikelen.ArtikelID equals at.ArtikelID
join sa in dc.ShopArtikels on artikelen.ArtikelID equals sa.ArtikelID
join cat in dc.Categories on artikelen.CategorieID equals cat.CategorieID
join catt in dc.CategorieTaals on cat.CategorieID equals catt.CategorieID
join sh in dc.Shops on sa.ShopId equals sh.ShopID
join catgs in dc.CategorieGroepShops on sh.ShopID equals catgs.ShopId
join tl in dc.Taals on new { tc1 = at.TaalCode, tc2 = catt.TaalCode } equals new { tc1 = tl.TaalCode, tc2 = tl.TaalCode }
join catgt in dc.CategorieGroepTaals on new { tl.TaalCode, catgs.CategorieGroepId } equals new { catgt.TaalCode, catgt.CategorieGroepID }
join catg in dc.CategorieGroeps on new { cat.CategorieGroepID, catgt.CategorieGroepID, catgs.CategorieGroepId } equals new { catg.CategorieGroepID, catg.CategorieGroepID, catg.CategorieGroepID }
where sh.ShopID == 230
select dc.Artikels;
but I have a syntax error after "dut" }
Edit 2:
changed the join and replaced "dut" with the corresponding field in the database.
still have the error after the first }
it says: type inference failed in the call to 'Join'
Some of the SQL joins have multiple join conditions, which you didn't put in the LINQ query.
If this is something that will be frequently run then you should rewrite it as a stored procedure. I believe it is too convoluted and complex for a LINQ statement - too hard to see what's going on.
There is a tool for it, but I didn't try it. May be it's usefull for you.
http://www.sqltolinq.com/
It looks like the error line is actually a "Where" cause but not "Joining".
You can actually split the whole long Linq statement into smaller Query.
so for this case, its better to split it like this:
var at = from a in dc.ArtikelTaals
where a.TaalCode == "dut"
select a;
var catt = from c in dc.CategorieTaals
where c.TaalCode == "dut"
select c;
.....
and you can join the IQueryable "at" and "catt" in your complex query later.