When I run the Linq query on LinqPad it takes only 4-5 seconds to return 5000 rows but when I run that same query in my code using Entity Framework it throws timeout.
What could be the possible issues?
Thanks in advance.
Below is the query:
var resultSale =
from product in Products
join productInfo in ProductInfoSummaries on product.ID equals productInfo.ProductID
join productDetail in ProductDetails on new { Id = product.ID, storeId = product.CreatedInStore } equals new { Id = productDetail.ProductID, storeId = productDetail.StoreID }
join productInventoryOtherStore in InventoryOtherStores on product.ID equals productInventoryOtherStore.ProductID
into productInventories
from productInventoryOtherStore in productInventories.DefaultIfEmpty()
join saleLine in SaleLines on productDetail.ID equals saleLine.ArtikkelNr
join sales in Sales on saleLine.OrderID equals sales.ID
where saleLine.ArtikkelNr != null
&& saleLine.DatoTid >= new DateTime(2018, 01, 01)
&& saleLine.DatoTid <= new DateTime(2019,11,21)
&& sales.StoreID == 14
&& (sales.OrderType == 1 || sales.OrderType == 2 || sales.OrderType == 4 || sales.OrderType == 6)
&& productDetail.SupplierProductNo != null
&& productDetail.Deleted == null
&& (productInfo.Inactive == null || productInfo.Inactive == false)
&& (product.CreatedInStore == 14 || product.CreatedInStore == 0 || product.CreatedInStore == null)
group new { saleLine.AntallEnheter, sales.OrderType } by new { product.ID, productInventoryOtherStore.Amount } into g
select new ProductSaleSummaryVM
{
ID = g.Key.ID,
Inventory = (double)g.Key.Amount,
TotalSold = g.Sum(x => x.OrderType !=4 ? x.AntallEnheter : 0) ?? 0,
TotalWastage = g.Sum(x => x.OrderType ==4 ? x.AntallEnheter : 0) ?? 0,
TotalOrderedQty = 0
};
var resultSupplierOrder =
from supplierOrderLine in SupplierOrderLines
join supplierOrder in SupplierOrders on supplierOrderLine.SupplierOrderID equals supplierOrder.ID
where supplierOrderLine.Deleted == null
&& supplierOrder.Status != 1
&& supplierOrder.StoreID == 14
group supplierOrderLine by supplierOrderLine.ProductID into g
select new ProductOrderDetailsVM
{
ID = g.Key,
TotalOrderedQty = (double)g.Sum(x => x.ConsumerQuantity - x.QuantiyReceived)
};
var r =
(from resSale in resultSale
join resSupplierOrder in resultSupplierOrder on resSale.ID equals resSupplierOrder.ID
into resSupplierOrders
from resSupplierOrder in resSupplierOrders.DefaultIfEmpty()
orderby resSale.ID
select new ProductSaleSummaryVM
{
ID = resSale.ID,
Inventory = resSale.Inventory,
TotalSold = resSale.TotalSold,
TotalWastage = resSale.TotalWastage,
TotalOrderedQty = resSupplierOrder.TotalOrderedQty ?? 0
})
.Where(x => x.Inventory + x.TotalOrderedQty < x.TotalSold);
r.Dump();
Try using entity framework within linqpad see if it gives you any clues. see this link on how to use entity framework in linqpad
https://www.linqpad.net/EntityFramework.aspx
This behaviour could be related to parameter sniffing - check this article for details
Related
I want to assign GetMajorMileStone(projecttask.ProjectTaskId) result to MajorMilestone.
I tried but getting following error:
LINQ to Entities does not recognize the method
'System.Data.Objects.ObjectResult1[.Poco.GetMajorMileStone_Result]
GetMajorMileStone(System.Nullable1[System.Guid])' method, and this
method cannot be translated into a store expression.'
Here is my code:
public ProjectsPayload GetProjectSchedule(int projectid, bool includeArchived, DateTime startDate, DateTime endDate, int userId)
{
using (var db = new Entities())
{
try
{
db.CommandTimeout = 1200;
var query = from project in db.Project.Where(t => (t.Active || t.TempActive) && t.ProjectId == projectid)
join UP in db.User_X_Project on project.ProjectId equals UP.ProjectId
where (UP.UserId == userId && UP.Active)
orderby (project.Priority ?? int.MaxValue)
orderby (project.ProjectTitle)
select new
{
Project = project,
ProjectTask = from projecttask in project.ProjectTask.Where(t => t.Active && (
(includeArchived == true && t.TaskStatusId == (int?)TaskStatus.Archived) ||
(includeArchived == false && t.TaskStatusId != (int?)TaskStatus.Archived))
|| t.TaskStatusId != (int?)TaskStatus.Planned)
join schedule in project.ProjectTask.SelectMany(p => p.ProjectTaskSchedule) on projecttask.ProjectTaskId equals schedule.ProjectTaskId
join daily in db.ProjectTaskSchedule.SelectMany(p => p.DailyStatus) on schedule.ProjectTaskScheduleId equals daily.ProjectTaskScheduleId
where schedule.Active && daily.Active && projecttask.Active && schedule.ResourceId == userId && (
(EntityFunctions.TruncateTime(daily.Date) >= EntityFunctions.TruncateTime(startDate.Date) &&
EntityFunctions.TruncateTime(daily.Date) <= EntityFunctions.TruncateTime(endDate.Date))
)
orderby schedule.StartDate
select new
{
ProjectTask = projecttask,
ProjectTaskSchedule = from projecttaskschedule in projecttask.ProjectTaskSchedule.Where(t => t.Active && t.ResourceId == userId)
select new
{
ProjectTaskSchedule = projecttaskschedule,
DailyStatus = projecttaskschedule.DailyStatus.Where(t => t.Active),
},
CritiCality = from cr in db.CritiCality.Where(ts => ts.ProjectTaskId == projecttask.ProjectTaskId) select cr,
MMDetails = from mm in db.MMDetails.Where(ts => ts.ProjectTaskId == projecttask.ProjectTaskId) select mm,
MajorMilestone = db.GetMajorMileStone(projecttask.ProjectTaskId).FirstOrDefault(),
}
};
var materialized = query.AsEnumerable();
var result = materialized.Select(t => new ProjectsPayload
{
ProjectId = t.Project.ProjectId,
ProjectTitle = t.Project.ProjectTitle,
Priority = t.Project.Priority,
ProjectDescription = t.Project.ProjectDescription,
ProjectTask = t.Project.ProjectTask.Select(x => new ProjectTaskPayload
{
Duration = x.Duration,
Hours = x.Hours,
IsOngoing = x.IsOngoing,
IsSummaryTask = x.IsSummaryTask,
Priority = x.Priority,
ParentTaskId = x.ParentTaskId,
ProjectId = x.ProjectId,
ProjectTaskId = x.ProjectTaskId,
TaskAcceptanceId = x.TaskAcceptanceId,
TaskStatusId = x.TaskStatusId,
TaskTitle = x.TaskTitle,
TaskTypeId = x.TaskTypeId,
IsMileStone = x.IsMileStone,
IsTimeAwayTask = x.IsTimeAwayTask,
AutoSize = x.AutoSize,
IsArchivedTasksInSummary = x.IsArchivedTasksInSummary,
IsASAP = x.IsASAP,
IsAutoCompleteEnable = x.IsAutoCompleteEnable,
IsSharedDiffSchedules = x.IsSharedDiffSchedules,
LongDescription = x.LongDescription,
OwnerId = x.OwnerId,
ShowInSummaryTask = x.ShowInSummaryTask,
SubTypeID = x.SubTypeID,
MMDetails1 = x.MMDetails1.Select(MD => new MMDetailsPayload { MajorMilestoneId = MD.MajorMilestoneId, ProjectTaskId = MD.ProjectTaskId, MMDetailsId = MD.MMDetailsId, Slack = MD.Slack }),
ProjectTaskSchedule = x.ProjectTaskSchedule.Select(a => new ProjectsTaskSchedulePayload
{
ProjectTaskScheduleId = a.ProjectTaskScheduleId,
StartDate = a.StartDate,
EndDate = a.EndDate,
ProjectTaskId = a.ProjectTaskId,
ResourceId = a.ResourceId,
ArchiveEndDate = a.ArchiveEndDate,
ArchiveStartDate = a.ArchiveStartDate,
IsSharedTask = a.IsSharedTask,
TimeUnitId = a.TimeUnitId,
DailyStatus = a.DailyStatus.Select(Ds => new DailyStatusPayload
{
Active = Ds.Active,
ActualHours = Ds.ActualHours,
DailyStatusId = Ds.DailyStatusId,
Date = Ds.Date,
ProjectTaskScheduleId = Ds.ProjectTaskScheduleId,
IsCloseOutDay = Ds.IsCloseOutDay,
Priority = Ds.Priority
})
}).ToList(),
CritiCality = x.CritiCality.Select(c => new CriticalityPayload { CriticalityId = c.CriticalityId, CriticalityTypeId = c.CriticalityTypeId, ProjectTaskId = c.ProjectTaskId }).ToList(),
}).ToList()
}).FirstOrDefault();
return result;
}
catch (EntityException ex)
{
if (ex.Message == connectionException)
throw new FaultException(dbException);
else
throw new FaultException(ex.Message);
}
}
}
My result is like this, I want all entities(Criticality,MMDetails and MajorMileStone), Not only MajorMileStone
MajorMileStone Result
I separate multiple simple query for testing. Please try to execute below two query and check whether successful or not.
// First query to get project
var query1 = from project in db.Project.Where(t => (t.Active || t.TempActive) && t.ProjectId == projectid)
join UP in db.User_X_Project on project.ProjectId equals UP.ProjectId
where (UP.UserId == userId && UP.Active)
orderby (project.Priority ?? int.MaxValue)
orderby (project.ProjectTitle)
.Select new { project = project }.ToList();
// Second query to get projecttask from query1.project and execute store procedure
var query2 = from projecttask in query1.project.ProjectTask.Where(t => t.Active && (
(includeArchived == true && t.TaskStatusId == (int?)TaskStatus.Archived) ||
(includeArchived == false && t.TaskStatusId != (int?)TaskStatus.Archived)) ||
t.TaskStatusId != (int?)TaskStatus.Planned)
join schedule in query1.project.ProjectTask.SelectMany(p => p.ProjectTaskSchedule) on projecttask.ProjectTaskId equals schedule.ProjectTaskId
join daily in db.ProjectTaskSchedule.SelectMany(p => p.DailyStatus) on schedule.ProjectTaskScheduleId equals daily.ProjectTaskScheduleId
where schedule.Active && daily.Active && projecttask.Active && schedule.ResourceId == userId && (
(EntityFunctions.TruncateTime(daily.Date) >= EntityFunctions.TruncateTime(startDate.Date) &&
EntityFunctions.TruncateTime(daily.Date) <= EntityFunctions.TruncateTime(endDate.Date))
)
orderby schedule.StartDate
.Select new
{
MajorMilestone = db.GetMajorMileStone(projecttask.ProjectTaskId).FirstOrDefault(),
}.ToList();
Let me know it has result or not. In the meantime you can check this "Method cannot be translated into a store expression"
It has link to article about what not to do with linq. Nested Linq like this is best to avoid and better to split up the query. If it affects the execution time, it better to execute raw sql.
We have some Machines having Devices attached. Not all the machines have devices atached and the devices cand be moved between machines. The devices generate Errors and we need to count those errors occured in the past day.
We have four tables: Machines (with Id and Code), Devices (with Id and Code), a pairing table DevicesMachines (Id, IdMachine, IdDevice, From datetime, To datetime) and Errors(Id, IdDevice, Moment datetime, Description).
The working SQL query is this:
Select m.Id, m.Code,
Coalesce(d.Code, 'NA') As DeviceCode,
Coalesce(Err.ErrorCnt,0) As ErrorCnt
From Machines As m
Left Outer Join (Select IdMachine, IdDevice From DevicesMachines as dm
Where GetDate() Between dm.From And dm.To) As dm on m.Id=dm.IdMachine
Left Outer Join Devices As d on dm.IdDevice=d.Id
Left outer join
( Select IdMachine, Count(Id) As ErrorCnt From Errors as er
Where er.Moment >= DateAdd(day,-1,GetUtcDate())
Group By IdMachine) As Err
On m.Id=Err.IdMachine
I have tried many syntaxes, one of which is below:
using ( DataContextM dcMachines = new dataContextM())
{
IEnumerable<MachineRow> lstM =
from m in dcMachines.Machines
from dm in dcMachines.DevicesMachines.Where(dm => (dm.IdMachine == m.Id) && (dm.From <= DateTime.Now) && (dm.To >= DateTime.Now)).DefaultIfEmpty()
from d in dcMachines.Devices.Where(d => d.Id == dm.IdDevice).DefaultIfEmpty()
from er in dcMachines.Errors
.Where(er => (er.Moment >= DateTime.Now) && (er.Moment <= DateTime.Now.AddDays(-1)))
.GroupBy(er => er.IdMachine)
.Select(er => new { IdMachine = er.Key, ErrorCnt = er.Count() })
.Where(er=> er.IdMachine==m.Id).DefaultIfEmpty()
select new MachineRow
{
Id = amId,
Code = m.Code,
DeviceCode = (d == null) ? "NA" : d.DeviceCode,
IdDevice = (d == null) ? 0: d.Id,
ErrorCnt = (er == null) ? 0 : er.ErrorCnt
};
}
I failed to find the right Linq syntax and I need your help.
Thank you,
Daniel
Based on the SQL you provided, I created what I think is the equivalent EF LINQ expression:
using (var dcMachines = new DataContextM())
{
var now = DateTime.Now;
var utcYesterday = DateTime.UtcNow.AddDays(-1);
var devicesMachinesQuery =
from dm in dcMachines.DevicesMachines
where dm.From <= now && dm.To >= now
join d in dcMachines.Devices on dm.IdDevice equals d.Id into dItems
from d in dItems.DefaultIfEmpty()
select new
{
dm.IdMachine,
dm.IdDevice,
DeviceCode = d != null ? d.Code : "NA"
};
var errorsQuery =
from err in dcMachines.Errors
where err.Moment >= utcYesterday
select err;
IEnumerable<MachineRow> lstM =
from m in dcMachines.Machines
join dm in devicesMachinesQuery on m.Id equals dm.IdMachine into dmItems
from dm in dmItems.DefaultIfEmpty()
select new MachineRow
{
Id = m.Id,
Code = m.Code,
DeviceCode = dm != null ? dm.DeviceCode : "NA",
IdDevice = dm != null ? dm.IdDevice : 0,
ErrorCnt = (
from err in errorsQuery
where err.IdMachine == m.Id
select err.Id
)
.Count()
};
}
I made some tests in memory and it seems to yield the same behavior as your provided SQL query.
I want to implement the following SQL statement using entity framework:
select coalesce(SUM(cdin_ActMortgageAmnt), 0)
from CRM.dbo.CDIndex,CRM.dbo.company
where comp_companyid = cdin_companyid
and comp_idcust like '%10319%'
and cdin_Deleted is null
and cdin_startunstufdate is not null
and cdin_Status = 'InProgress'
I tried to get the sum of cdin_ActMortgageAmnt:
Company c = db.Companies.Find(750);
var CGP = (from cd in db.CDIndexes
join com in db.Companies on cd.cdin_CompanyId equals com.Comp_CompanyId
where com.Comp_IdCust == c.Comp_IdCust &&
cd.cdin_Deleted == null &&
cd.cdin_startunstufdate == null &&
cd.cdin_Status == "InProgress"
select new
{
act = cd.cdin_ActMortgageAmnt == null ? 0 : cd.cdin_ActMortgageAmnt
}
);
var query = CGP.Sum(x => x.act);
lblSum.Text = query.ToString();
But the query returns null while tracing...
I read a lot about getting a readable sql server query string from a c# linq to sql function, but could not figure out how to actually do so, maybe because the project i am working on is really complicated.
I'm pasting a pice of a code that i want to convert to sql (select * from bonds join etc.)
public List<EntBondPortfolio> GetBondsForPortfolio(List<int> groups, List<int> ratings,
List<int> collaterals, List<int> companies, List<int> countries, List<int> fields,
List<int> currencies, DateTime? fromExpirationDate, DateTime? untilExpirationDate, bool? perpetual, int? sortOrder = 1)
{
// Get Bonds
return (from bond in DALLinqClasses.Instance.BONDs
join company in DALLinqClasses.Instance.COMPANies on bond.Company_ID equals company.CompanyID
into companyJoin
from companyJ in companyJoin.DefaultIfEmpty()
join sellBuy in DALLinqClasses.Instance.SELL_BUY_OPERATIONs on bond.BondID equals sellBuy.Investment_ID
join account in DALLinqClasses.Instance.BANK_ACCOUNTs on sellBuy.BankAccount_ID equals account.BankAccountID
join groupsTable in DALLinqClasses.Instance.GROUPs on account.GroupAccount_ID equals groupsTable.GroupID
join customer in DALLinqClasses.Instance.CUSTOMERs on groupsTable.Customer_ID equals customer.CustomerID
join rating in DALLinqClasses.Instance.RATINGs on bond.Rating_ID equals rating.RatingID
into ratingJoin
from ratingJ in ratingJoin.DefaultIfEmpty()
join currency in DALLinqClasses.Instance.CURRENCies on bond.Currency_ID equals currency.CurrencyID
join country in DALLinqClasses.Instance.COUNTRies on bond.Country_ID equals country.CountryID
into countryJoin
from countryJ in countryJoin.DefaultIfEmpty()
join field in DALLinqClasses.Instance.FIELDs on bond.Field_ID equals field.FieldID
into fieldJoin
from fieldJ in fieldJoin.DefaultIfEmpty()
join collateral in DALLinqClasses.Instance.RISC_LEVELs on bond.RiscLevel_ID equals collateral.RiscLevelID
into collateralJoin
from collateralJ in collateralJoin.DefaultIfEmpty()
join orderi in // For order by
DALLinqClasses.Instance.PORTFOLIO_ORDERs.Where(x => x.InvestmentType_ID == (int)INVESTMENT_TYPES.BONDS)
on new EntTwoInts { BankAccountID = bond.BondID, GroupID = groupsTable.GroupID }
equals
new EntTwoInts { BankAccountID = orderi.Investment_ID, GroupID = orderi.Group_ID }
into orderJoin
from orderJ in orderJoin.DefaultIfEmpty()
where sellBuy.InvestmentType_ID == (int)INVESTMENT_TYPES.BONDS
&& groups.Contains(groupsTable.GroupID)
&& (collaterals.Contains(bond.RiscLevel_ID ?? -1) || collaterals.Contains(-1))
&& (ratings.Contains(bond.Rating_ID ?? -1) || ratings.Contains(-1))
&& (companies.Contains(bond.Company_ID ?? -1) || companies.Contains(-1))
&& (countries.Contains(bond.Country_ID ?? -1) || countries.Contains(-1))
&& (fields.Contains(bond.Field_ID ?? -1) || fields.Contains(-1))
&& (currencies.Contains(bond.Currency_ID) || currencies.Contains(-1))
&& (bond.ExpirationDate >= fromExpirationDate || fromExpirationDate == null)
&& (bond.ExpirationDate <= untilExpirationDate || untilExpirationDate == null)
&& (perpetual == bond.Perpetual || perpetual == null)
group sellBuy by new { bond, companyJ, groupsTable, account, orderJ, customer, ratingJ, collateralJ, countryJ, fieldJ } into g
orderby g.Key.orderJ != null ? false : true, g.Key.orderJ.SortOrder, g.Key.groupsTable.GroupName, g.Key.companyJ.CompanyName
select new EntBondPortfolio
{
Rating = g.Key.ratingJ.RatingName,
RiscLevel = g.Key.collateralJ.RiscLevelName,
Group = g.Key.groupsTable.GroupName,
Client = g.Key.customer.FirstName + ' ' + g.Key.customer.LastName,
GroupId = g.Key.groupsTable.GroupID,
Company = g.Key.companyJ.CompanyName,
CurrencyId = g.Key.bond.Currency_ID,
BondId = g.Key.bond.BondID,
CallText = g.Key.bond.CallText,
Field = g.Key.fieldJ.FieldName,
Country = g.Key.countryJ.CountryName,
CouponPercent = g.Key.bond.CouponPercent,
// Get total sum of coupons in checking account of current bond
CouponsPaid = DALLinqClasses.Instance.CHECKING_ACCOUNTs.
Where(x => x.ActionType_ID == (int)ACTION_TYPES.COUPON
&& g.Select(y => y.SellBuyOperationID).
Contains(x.SellBuyOperation_ID.GetValueOrDefault()))
.Sum(s => s.ActualSum),
ExpirationDate = g.Key.bond.ExpirationDate,
FaceValue = (g.Where(x => x.IsSell == false).Sum(x => x.FaceValue) - (g.Where(x => x.IsSell == true).Sum(x => x.FaceValue) ?? 0)),
Isin = g.Key.bond.Isin,
LastBuyDate = g.Where(x => x.IsSell == false).Max(x => x.SellBuyOperationDate),
CurrentPrice = DALInvestmentTypes.Instance.GetCurrentPriceOfBond(g.Key.bond.BondID, BONDS_HISTORY_TYPES.MarketValue),
CurrentYield = DALInvestmentTypes.Instance.GetCurrentPriceOfBond(g.Key.bond.BondID, BONDS_HISTORY_TYPES.Yield),
CurrentAcrInterest = DALInvestmentTypes.Instance.GetCurrentPriceOfBond(g.Key.bond.BondID, BONDS_HISTORY_TYPES.AcrInterest),
PurchasePrice = g.Where(x => x.IsSell == false).Sum(x => x.FaceValue) == 0 ? 0 :
g.Where(x => x.IsSell == false).Sum(x => x.FaceValue * x.Price)
/ g.Where(x => x.IsSell == false).Sum(x => x.FaceValue),
Instruction = DALInstructions.Instance.IsInvestmentHaveInstruction(INVESTMENT_TYPES.BONDS, g.Key.bond.BondID, g.Key.account.BankAccountID),
}).ToList();
}
I have this linq query:
var sku = (from a in con.MagentoStockBalances
join b in con.MFGParts on a.SKU equals b.mfgPartKey
join c in con.DCInventory_Currents on b.mfgPartKey equals c.mfgPartKey
where a.SKU != 0 && c.dcKey ==6
select new
{
Part_Number = b.mfgPartNumber,
Stock = a.stockBalance,
Recomended = a.RecomendedStock,
Cato = c.totalOnHandQuantity
}).ToList();
Now i need to remove the c.dcKey ==6 condition and have something like this:
var sku = (from a in con.MagentoStockBalances
join b in con.MFGParts on a.SKU equals b.mfgPartKey
join c in con.DCInventory_Currents on b.mfgPartKey equals c.mfgPartKey
where a.SKU != 0
select new
{
Part_Number = b.mfgPartNumber,
Stock = a.stockBalance,
Recomended = a.RecomendedStock,
Cato = c.totalOnHandQuantity where c.dcKey == 6,
Kerry = c.totalOnHandQuantity where c.dcKey == 7
}).ToList();
Something like this:
Cato = c.dcKey == 6 ? c.totalOnHandQuantity : 0,
Kerry = c.dcKey == 7 ? c.totalOnHandQuantity : 0
The ?: syntax is called a conditional operator.
Instead of adding another join, I would use a separate query in a let:
from a in con.MagentoStockBalances
join b in con.MFGParts on a.SKU equals b.mfgPartKey
where a.SKU != 0
let cs = con.DCInventory_Currents.Where(c => b.mfgPartKey == c.mfgPartKey)
select new
{
Part_Number = b.mfgPartNumber,
Stock = a.stockBalance,
Recomended = a.RecomendedStock,
Cato = cs.Single(c => c.dcKey == 6).totalOnHandQuantity
Kerry = cs.Single(c => c.dcKey == 7).totalOnHandQuantity
}
Though I have no idea how well will LINQ to SQL handle a query like this (if it handles it at all).
var query= from x in context.a
where String.IsNullOrEmpty(param1) || (x.p == param1 && x.i == param2)
select x;