OR clause in the LINQ query is causing performance issue. If I change it to Union performance improves a lot. Here is current query. How do I convert (includeBatch && i.BatchId != null || includeSingle && i.BatchId == null) this part of query to Union.
Original Call:
var inputs = _inputRepository.GetProcessorQueue(includeBatch, includeSingle, companyIds);
Current Solution: Making two calls and doing union operation
if (includeSingle && includeBatch)
{
var inputsSingle = _inputRepository.GetProcessorQueue(false, includeSingle, companyIds);
var inputsBatch = _inputRepository.GetProcessorQueue(includeBatch, false, companyIds);
return inputsSingle.Union(inputsBatch).ToList();
}
else
{
var inputs = _inputRepository.GetProcessorQueue(includeBatch, includeSingle, companyIds);
return inputs.Select(Input.ToQueueInputExpression(inputQueueMetaDataTypes)).ToList();
}
Original LINQ:
public IQueryable<Input> GetProcessorQueue(bool includeBatch, bool includeSingle, int[] companyIds)
{
return FindAsQueryableReadOnly(i => !i.IsDeleted
&& i.InputTypeId == (int)InputType.Values.TRANSPORTATION
&& i.ExportedStatusId != (int)ExportedStatus.Values.EXPORTED
&& ImportStatus.DataEntryQueue.Contains(i.ImportStatusId)
&& ((i.TransportationInput.TransportationInputTypeId == (int)TransportationInputType.Values.FACTOR
&& (includeBatch && i.BatchId != null || includeSingle && i.BatchId == null)
&& !i.DocumentOnlyStatus)
|| (includeBatch && i.BatchId != null && i.DocumentOnlyStatus && i.InputDocumentStats.DocumentId != null)
)
&& (companyIds == null || !companyIds.Any() || companyIds.Contains(i.CompanyId)),
i => i.Batch,
i => i.ImportStatus,
i => i.InputCharges,
i => i.InputDocumentStats,
i => i.InputDocumentStats.DocumentOrigin,
i => i.InputDocumentStats.Document.DocumentMetaData);
}
Original SQL: (removed select statement for readability)
FROM [eroom].[Input] AS [i]
INNER JOIN [eroom].[ImportStatus] AS [i.ImportStatus] ON [i].[ImportStatusId] = [i.ImportStatus].[ImportStatusId]
LEFT JOIN [eroom].[Batch] AS [i.Batch] ON [i].[BatchId] = [i.Batch].[BatchId]
LEFT JOIN [eroom].[InputDocumentStats] AS [i.InputDocumentStats] ON [i].[InputId] = [i.InputDocumentStats].[InputId]
LEFT JOIN [eroom].[DocumentOrigin] AS [i.InputDocumentStats.DocumentOrigin] ON [i.InputDocumentStats].[DocumentOriginId] = [i.InputDocumentStats.DocumentOrigin].[DocumentOriginId]
LEFT JOIN [eroom].[Document] AS [i.InputDocumentStats.Document] ON [i.InputDocumentStats].[DocumentId] = [i.InputDocumentStats.Document].[DocumentId]
LEFT JOIN [eroom].[TransportationInput] AS [i.TransportationInput] ON [i].[InputId] = [i.TransportationInput].[InputId]
WHERE ((((([i].[HiddenStatus] = 0) AND ([i].[InputTypeId] = 1)) AND ([i].[ExportedStatusId] <> 3)) AND [i].[ImportStatusId] IN (1, 4, 5, 7)) AND (((([i.TransportationInput].[TransportationInputTypeId] = 1) AND ([i].[BatchId] IS NOT NULL OR [i].[BatchId] IS NULL)) AND ([i].[DocumentOnlyStatus] = 0)) OR (([i].[BatchId] IS NOT NULL AND ([i].[DocumentOnlyStatus] = 1)) AND [i.InputDocumentStats].[DocumentId] IS NOT NULL))) AND [i].[CompanyId] IN (1, 2, 3)
Better performance SQL (removed select statement for readability)
FROM [eroom].[Input] AS [i]
INNER JOIN [eroom].[ImportStatus] AS [i.ImportStatus] ON [i].[ImportStatusId] = [i.ImportStatus].[ImportStatusId]
LEFT JOIN [eroom].[Batch] AS [i.Batch] ON [i].[BatchId] = [i.Batch].[BatchId]
LEFT JOIN [eroom].[InputDocumentStats] AS [i.InputDocumentStats] ON [i].[InputId] = [i.InputDocumentStats].[InputId]
LEFT JOIN [eroom].[DocumentOrigin] AS [i.InputDocumentStats.DocumentOrigin] ON [i.InputDocumentStats].[DocumentOriginId] = [i.InputDocumentStats.DocumentOrigin].[DocumentOriginId]
LEFT JOIN [eroom].[Document] AS [i.InputDocumentStats.Document] ON [i.InputDocumentStats].[DocumentId] = [i.InputDocumentStats.Document].[DocumentId]
LEFT JOIN [eroom].[TransportationInput] AS [i.TransportationInput] ON [i].[InputId] = [i.TransportationInput].[InputId]
WHERE ((((([i].[HiddenStatus] = 0) AND ([i].[InputTypeId] = 1)) AND ([i].[ExportedStatusId] <> 3)) AND [i].[ImportStatusId] IN (1, 4, 5, 7)) AND (((([i.TransportationInput].[TransportationInputTypeId] = 1) AND [i].[BatchId] IS NOT NULL) AND ([i].[DocumentOnlyStatus] = 0)) OR (([i].[BatchId] IS NOT NULL AND ([i].[DocumentOnlyStatus] = 1)) AND [i.InputDocumentStats].[DocumentId] IS NOT NULL))) AND [i].[CompanyId] IN (1, 2, 3)
UNION
FROM [eroom].[Input] AS [i]
INNER JOIN [eroom].[ImportStatus] AS [i.ImportStatus] ON [i].[ImportStatusId] = [i.ImportStatus].[ImportStatusId]
LEFT JOIN [eroom].[Batch] AS [i.Batch] ON [i].[BatchId] = [i.Batch].[BatchId]
LEFT JOIN [eroom].[InputDocumentStats] AS [i.InputDocumentStats] ON [i].[InputId] = [i.InputDocumentStats].[InputId]
LEFT JOIN [eroom].[DocumentOrigin] AS [i.InputDocumentStats.DocumentOrigin] ON [i.InputDocumentStats].[DocumentOriginId] = [i.InputDocumentStats.DocumentOrigin].[DocumentOriginId]
LEFT JOIN [eroom].[Document] AS [i.InputDocumentStats.Document] ON [i.InputDocumentStats].[DocumentId] = [i.InputDocumentStats.Document].[DocumentId]
LEFT JOIN [eroom].[TransportationInput] AS [i.TransportationInput] ON [i].[InputId] = [i.TransportationInput].[InputId]
WHERE ((((([i].[HiddenStatus] = 0) AND ([i].[InputTypeId] = 1)) AND ([i].[ExportedStatusId] <> 3)) AND [i].[ImportStatusId] IN (1, 4, 5, 7)) AND ((([i.TransportationInput].[TransportationInputTypeId] = 1) AND [i].[BatchId] IS NULL) AND ([i].[DocumentOnlyStatus] = 0))) AND [i].[CompanyId] IN (1, 2, 3)
public IQueryable<T> FindAsQueryableReadOnly(Expression<Func<T, bool>> where, params Expression<Func<T, object>>[] includeProperties)
{
IQueryable<T> query = _dbSet.AsQueryable();
query = IncludeProperties(includeProperties, query);
return query.Where(where).AsNoTracking();
}
Related
I have created a linq query to join tables and to do aggregate function and it takes more than a minute and it is affecting performance when executing the query in database it takes 18 seconds Kindly help me to improve the performance of Linq query.
Code:
List<int> oStatus = new List<int> { (int)STATUS.PAID, (int)STATUS.PARTIALY_PAID, (int)STATUS.OPEN, (int)STATUS.COMPLETED };
List<int> oLocationids = (
from loc in oTransactionContext.Location
join lum in oTransactionContext.LocationUserMap on loc.LocationId equals lum.LocationId
where lum.UserId == iUserID && loc.LocationName != "Local Purchase" && loc.LocationId !=0 &&loc.IsActive==true
select lum.LocationId
).ToList();
var oPT_Det = (
from inv in oTransactionContext.Invoice
join loc in oTransactionContext.Location on inv.LocationId equals loc.LocationId
where (inv.ClientId == (iClientID) && oLocationids.Contains(inv.LocationId.GetValueOrDefault()) &&
(inv.EndTime > DateTime.UtcNow.AddMonths(-6))
&& inv.IsActive == (true) && oStatus.Contains(inv.Status.GetValueOrDefault()))
group new { inv, loc } by new { inv.LocationId, loc.LocationName } into groupResult
select new OverAllSales
{
Location = Helper.CommonHelper.ParseString(groupResult.Key.LocationName),
InvoiceAmount = Helper.CommonHelper.ParseDecimal(groupResult.Sum(f => f.inv.TotalInvoiceAmount)),
}
).ToList();
Postgresql:
SELECT
COALESCE(SUM(inv.total_invoice_amount), 0) AS value1,
loc.location_name AS metric
FROM location loc
LEFT JOIN location_user_map LUM ON LUM.location_id = loc.location_id
LEFT OUTER JOIN invoice inv ON inv.client_id =2 AND inv.location_id = loc.location_id
AND inv.status IN (SELECT status_id FROM status WHERE status IN ('Paid', 'Partialy Paid', 'Open', 'Completed'))
WHERE loc.location_name NOT IN ('Local Purchase')
AND loc.location_id != 0
AND LUM.user_id IN ($user_ids)
AND inv.is_active = TRUE
AND CAST(inv.end_time AS date) > CURRENT_DATE - INTERVAL '2' MONTH
GROUP BY loc.location_name
ORDER BY value1 DESC
This is direct translation of the SQL. Should generate similar SQL query.
var startDate = DateTime.Date.AddMonths(-2);
int clientId = ...
int userId = ...
var oStatus = new List<int> { (int)STATUS.PAID, (int)STATUS.PARTIALY_PAID, (int)STATUS.OPEN, (int)STATUS.COMPLETED };
var query =
from loc in oTransactionContext.Location
join lum in oTransactionContext.LocationUserMap on loc.LocationId equals lum.LocationId
from inv in oTransactionContext.Invoice
.Where(inv => inv.ClientId == clientId && inv.LocationId = loc.LocationId
&& oStatus.Contains(inv.Status))
where
loc.LocationName != "Local Purchase"
&& loc.LocationId !=0
&& lum.UserId == userId
&& inv.IsActive == true
&& inv.end_time >= startDate
group inv by loc.LocationName into g
select new
{
Location = g.Key,
InvoiceAmount = g.Sum(x => x.total_invoice_amount) ?? 0
};
var oPT_Det = query.ToList();
I have this following query and want to convert to LINQ.
I have tried LINQPad and Linqer but getting an error in Visual Studio.
SELECT DISTINCT
g.TXT_Property,
up.TXT_Page
FROM MD g
LEFT JOIN MD ux ON ux.TXT_Page = #sPage
AND ux.TXT_Property = g.TXT_Property
AND ux.TXT_Product = #sProdAll
AND ux.GID_Section IS NULL
LEFT JOIN MD up ON up.TXT_Page = #sPage
AND up.TXT_Property = g.TXT_Property
AND (ISNULL(up.TXT_Product, '') = #sProd or up.TXT_Product = #sProdAlt)
AND up.GID_Section IS NULL
WHERE
(g.GID_Section IS NULL)
AND g.TXT_Page = #sPage
and (ISNULL(g.TXT_Product, '') = #sProd or g.TXT_Product = #sProdAlt or g.TXT_Product = #sProdAll)
ORDER BY TXT_Property, TXT_Product, TXT_Language
This what I have tried:
var query2 = from g in list
join ux in list
on g.Property equals ux.Property into g_ux
where ux.Page == sPage
&& ux.Product == sProdAll
&& ux.Section == null
And this is another try.
I have referred to
SQL to LINQ - multiple tables left outer join with where clause referring right table
// Another query
var query = (from g in
((from d in list
where ((d.Section == null || d.Section == uSection) && (d.Product == sProd || (sProd == "" && d.Product == null) || (d.Product == sProdAlt) || (d.Product == sProdAll)))
select (new { d.Property })).ToList())
join gx in
((from d in list
where (d.Section == null) && (d.Product == sProdAll)
select (new { d.Property, d.Page, d.Product, d.Language, d.Value, d.Section })).ToList())
on g.Property equals gx.Property into res1
from a1 in res1.DefaultIfEmpty()
join gp in
((from d in list
where (d.Section == null) && (d.Product == sProd || (sProd == "" && d.Product == null) || (d.Product == sProdAlt))
select (new { d.Property, d.Page, d.Product, d.Language, d.Value, d.Section })).ToList())
on g.Property equals gp.Property into res2
from a2 in res2.DefaultIfEmpty()
join ux in
((from d in list
where (d.Section == uSection) && (d.Product == sProdAll)
select (new { d.Property, d.Page, d.Product, d.Language, d.Value, d.Section })).ToList())
on g.Property equals ux.Property into res3
from a3 in res3.DefaultIfEmpty()
join up in
((from d in list
where (d.Section == uSection) && (d.Product == sProd || (sProd == "" && d.Product == null) || (d.Product == sProdAlt))
select (new { d.Property, d.Page, d.Product, d.Language, d.Value, d.Section })).ToList())
on g.Property equals up.Property into res4
from a4 in res4.DefaultIfEmpty()
orderby (new
{
TXT_Property = g.Property,
TXT_Product = Coalesce((Coalesce(a4.Page, "") == "" ? Coalesce(a4.Product, a3.Product) : Coalesce(a4.Product, "SA")), a3.Product, (Coalesce(a2.Page, "") == "" ? Coalesce(a2.Product, a1.Product) : Coalesce(a2.Product, "SA")), a1.Product),
TXT_Language = Coalesce(a4.Language, a3.Language, a2.Language, a1.Language),
})
select (new
{
TXT_Property = g.Property,
TXT_Product = Coalesce((Coalesce(a4.Page, "") == "" ? Coalesce(a4.Product, a3.Product) : Coalesce(a4.Product, "SA")), a3.Product, (Coalesce(a2.Page, "") == "" ? Coalesce(a2.Product, a1.Product) : Coalesce(a2.Product, "SA")), a1.Product),
TXT_Language = Coalesce(a4.Language, a3.Language, a2.Language, a1.Language),
TXT_Value = Coalesce(a4.Value, a3.Value, a2.Value, a1.Value)
}));
Your SQL query seems very questionable to me (since ux is a LEFT JOIN and (presumably) not referenced in the rest of the query, it adds nothing), and I had to assume the ORDER BY was on the g columns since it wasn't specified (and I am surprised that isn't rejected by SQL as ambiguous), but here is my try at the translation:
var ans = from g in MD
join ux in MD on new { TXT_Page = sPage, g.TXT_Property, TXT_Product = sProdAll, GID_Section = (string)null } equals new { ux.TXT_Page, ux.TXT_Property, ux.TXT_Product, ux.GID_Section } into uxj
from ux in uxj.DefaultIfEmpty()
join up in MD on new { TXT_Page = sPage, g.TXT_Property, GID_Section = (string)null } equals new { up.TXT_Page, up.TXT_Property, up.GID_Section } into upj
from up in upj.DefaultIfEmpty()
where up == null || (up.TXT_Product ?? "") == sProd || up.TXT_Product == sProdAlt
where g.GID_Section == null && g.TXT_Page == sPage &&
((g.TXT_Product ?? "") == sProd || g.TXT_Product == sProdAlt || g.TXT_Product == sProdAll)
orderby g.TXT_Property, g.TXT_Product, g.TXT_Language
select new { g.TXT_Property, up.TXT_Page };
Note: I put in the up == null because because otherwise the where might reject where the LEFT JOIN in SQL wouldn't.
I assumed the type of GID_Section was string, but you can cast the nulls to the right type.
Here is my SQL conversion recipe, though your SQL was a bit trickier since it combined LEFT JOIN and non-equijoin.
For translating SQL to LINQ query comprehension:
Translate FROM subselects as separately declared variables.
Translate each clause in LINQ clause order, translating monadic and aggregate operators (DISTINCT, TOP, MIN, MAX etc) into functions applied to the whole LINQ query.
Use table aliases as range variables. Use column aliases as anonymous type field names.
Use anonymous types (new { ... }) for multiple columns.
JOIN conditions that aren't all equality tests with AND must be handled using where clauses outside the join, or with cross product (from ... from ...) and then where
JOIN conditions that are multiple ANDed equality tests between the two tables should be translated into anonymous objects
LEFT JOIN is simulated by using into joinvariable and doing another from from the joinvariable followed by .DefaultIfEmpty().
Replace COALESCE with the conditional operator (?:)and a null test.
Translate IN to .Contains() and NOT IN to !...Contains(), using literal arrays or array variables for constant lists.
Translate x BETWEEN low AND high to low <= x && x <= high.
Translate CASE to the ternary conditional operator ?:.
SELECT * must be replaced with select range_variable or for joins, an anonymous object containing all the range variables.
SELECT fields must be replaced with select new { ... } creating an anonymous object with all the desired fields or expressions.
Proper FULL OUTER JOIN must be handled with an extension method.
i am trying to convert the following SQL into LINQ and need some assistance with the nested select clauses for the paid_amount and paid_vat and also for the select within the where clause. Ignore the index things.
here is the SQL
SELECT
tramps.gl_transaction.debtor_uri,
tramps.debtor.account_no,
tramps.gl_transaction.uri as transaction_uri,
tramps.gl_transaction.base_currency_amount,
tramps.gl_transaction.base_currency_vat_amount,
(select IsNull(sum(gltr.base_currency_amount), 0.00)
from tramps.gl_transaction gltr
where gltr.sibling_uri = tramps.gl_transaction.uri) * (-1) as Paid_Amount ,
(select IsNull(sum(gltr.base_currency_vat_amount), 0.00)
from tramps.gl_transaction gltr
where gltr.sibling_uri = tramps.gl_transaction.uri) * (-1) as Paid_Vat ,
tramps.account.property_ref,
tramps.account.sub_ledger_code,
tramps.gl_transaction.transaction_type_code,
tramps.gl_transaction.transaction_description,
tramps.gl_transaction.effective_date
FROM tramps.account, tramps.chart WITH (INDEX (PK_CHART)), tramps.gl_transaction WITH (INDEX (glt_debtor_gen)) ,tramps.debtor, tramps.receivables_register , tramps.bank_account
WHERE tramps.chart.code = tramps.account.chart_code
AND tramps.gl_transaction.debtor_uri = tramps.debtor.uri
AND tramps.gl_transaction.account_uri = tramps.account.uri
AND tramps.receivables_register.uri = tramps.gl_transaction.receivables_register_uri
AND tramps.receivables_register.bank_account_uri = tramps.bank_account.uri
AND tramps.chart.control_account = 'Debtor'
AND tramps.gl_transaction.status = 'L'
AND tramps.gl_transaction.process_status = 'Released'
AND ( (tramps.gl_transaction.generated = 'C' AND tramps.gl_transaction.sibling_uri IS NULL AND tramps.gl_transaction.written_off <> 'Y')
OR (tramps.gl_transaction.generated = 'N' AND tramps.gl_transaction.sibling_uri IS NULL) )
AND (tramps.gl_transaction.base_currency_amount +
(select IsNull(sum(gltr.base_currency_amount), 0.00)
from tramps.gl_transaction gltr
where gltr.sibling_uri = tramps.gl_transaction.uri) <> 0.00 )
this is the LINQ i have managed to create so far, but i am struggling with the nested selects, the sum and the where clause
from acc in Accounts
join chart in Charts on acc.Chart_code equals chart.Code
join gltrans in Gl_transactions on acc.Uri equals gltrans.Account_uri
join debt in Debtors on gltrans.Debtor_uri equals debt.Uri
join recreg in Receivables_registers on gltrans.Receivables_register_uri equals recreg.Uri
join bankacc in Bank_accounts on recreg.Bank_account_uri equals bankacc.Uri
let paidcurrency = from gltrns in Gl_transactions
where gltrns.Sibling_uri == gltrans.Uri
select gltrns.Base_currency_amount
where
chart.Control_account == "Debtor"
&& gltrans.Status == "L"
&& gltrans.Process_status == "Released"
&& acc.Property_ref == 102979
&& ((gltrans.Generated == "C" && gltrans.Sibling_uri == null && gltrans.Written_off != "Y")
|| (gltrans.Generated == "N" && gltrans.Sibling_uri == null) )
select new
{
gltrans.Debtor_uri,
debt.Account_no,
gltrans.Uri,
gltrans.Base_currency_amount,
gltrans.Base_currency_vat_amount,
er = (decimal?)paidcurrency.Base_currency_vat_amount.Sum() ?? 0,
acc.Property_ref,
acc.Sub_ledger_code,
gltrans.Transaction_type_code,
gltrans.Transaction_description,
gltrans.Effective_date
}
This might help out a little. I blended in some fluent syntax to help translate the Sum functions. Let me know if some of these translations help as I can't check it directly without your schema and some data.
var result =
from acc in Accounts
join chart in Charts on acc.Chart_code equals chart.Code
join gltrans in Gl_transactions on acc.Uri equals gltrans.Account_uri
join debt in Debtors on gltrans.Debtor_uri equals debt.Uri
join recreg in Receivables_registers on gltrans.Receivables_register_uri equals recreg.Uri
join bankacc in Bank_accounts on recreg.Bank_account_uri equals bankacc.Uri
// query expression
//let paidcurrency = from gltrns in Gl_transactions
// where gltrns.Sibling_uri == gltrans.Uri
// select gltrns.Base_currency_amount
// change to fluent..
let paid_Amount = gltrans.Where(g => g.Sibling_uri == g.Uri)
.Select(g => g.Base_currency_amount * -1 ?? 0.00M).Sum()
// same for Vat..
let paid_Vat = gltrans.Where(g => g.Sibling_uri == g.Uri)
.Select(g => g.Base_currency_vat_amount * -1 ?? 0.00M).Sum()
// added another 'let' to use in the where clause..
let base_Currency = gltrans.Where(g => g.Sibling_uri == g.Uri)
.Select(g => g.Base_currenct_amount ?? 0.00M).Sum()
where
chart.Control_account == "Debtor"
&& gltrans.Status == "L"
&& gltrans.Process_status == "Released"
&& acc.Property_ref == 102979
&& (
(
gltrans.Generated == "C" &&
gltrans.Sibling_uri == null &&
gltrans.Written_off != "Y"
)
||
(
gltrans.Generated == "N" &&
gltrans.Sibling_uri == null
)
)
&& gltrans.Base_currency_amount + base_Currency != 0.00M
select new
{
gltrans.Debtor_uri,
debt.Account_no,
gltrans.Uri,
gltrans.Base_currency_amount,
gltrans.Base_currency_vat_amount,
//er = (decimal?)paidcurrency.Base_currency_vat_amount.Sum() ?? 0,
paid_Amount,
paid_Vat,
acc.Property_ref,
acc.Sub_ledger_code,
gltrans.Transaction_type_code,
gltrans.Transaction_description,
gltrans.Effective_date
};
I have a LINQ query. But I need to get value of two columns from another subquery. This is my Linq query:
)from t in db.PUTAWAYs
join t0 in db.ASN_ITEM on t.AWB_NO equals t0.AWB_NO
join t1 in db.ASN_MASTER on t0.AWB_NO equals t1.AWB_NO
join t2 in db.ITEM_MASTER on t.ITEM_MASTER.ITEM_CODE equals t2.ITEM_CODE
join t3 in db.ASN_INPUT on t0.AWB_NO equals t3.AWB_NO
where
t3.ITEM == t2.ITEM_CODE &&
1 == 1 &&
(fromDate == "" || toDate == "" || (t0.REC_DATE.CompareTo(fromDate) >= 0 && t0.REC_DATE.CompareTo(toDate) <= 0)) &&
(AWB_NO == "" || (t0.AWB_NO == AWB_NO))
orderby
t.AWB_NO,
t0.REC_DATE,
t0.STYPE,
t2.PART_NO
select new ASNPutawayRep
{
AWB_NO = t.AWB_NO,
REC_DATE = t0.REC_DATE,
STYPE = t0.STYPE,
PART_NO = t2.PART_NO,
//LOCATION_AD = t.LOCATION_AD,
QNTY = t.QNTY,
//LOCATION_SD = t.LOCATION_SD,
REGION_ID = t.REGION_ID
}).Distinct();
Here in select portion of above query, instead of directly taking value of the column t.LOCATION_AD, I need to get it from SELECT LOC_NAME FROM LOCATION_MASTER WHERE LOC_CODE = t.LOCATION_AD
and instead of t.LOCATION_SD, I need to get value from SELECT LOC_NAME FROM LOCATION_MASTER where LOC_CODE = t.LOCATION_SD
How can I write this in LINQ. Is there any way to do this?
You can make use of let clause. It is useful to store the result of sub-expression in order to use it in subsequent clauses.
Example:
(from t in db.PUTAWAYs
...
let locAd = from l in LOCATION_MASTER where LOC_CODE = t.LOCATION_SD select l.LOC_NAME
where
...
orderby
...
select new ASNPutawayRep
{
LOCATION_AD = locAd,
}).Distinct();
Also, you can directly write LINQ without using let clause:
(from t in db.PUTAWAYs
...
where
...
orderby
...
select new ASNPutawayRep
{
LOCATION_AD = from l in LOCATION_MASTER where LOC_CODE = t.LOCATION_SD select l.LOC_NAME
}).Distinct();
You can use AsQueryable to achieve this
from t in db.PUTAWAYs
join t0 in db.ASN_ITEM on t.AWB_NO equals t0.AWB_NO
join t1 in db.ASN_MASTER on t0.AWB_NO equals t1.AWB_NO
join t2 in db.ITEM_MASTER on t.ITEM_MASTER.ITEM_CODE equals t2.ITEM_CODE
join t3 in db.ASN_INPUT on t0.AWB_NO equals t3.AWB_NO
where
t3.ITEM == t2.ITEM_CODE &&
1 == 1 &&
(fromDate == "" || toDate == "" || (t0.REC_DATE.CompareTo(fromDate) >= 0 && t0.REC_DATE.CompareTo(toDate) <= 0)) &&
(AWB_NO == "" || (t0.AWB_NO == AWB_NO))
orderby
t.AWB_NO,
t0.REC_DATE,
t0.STYPE,
t2.PART_NO
select new ASNPutawayRep
{
AWB_NO = t.AWB_NO,
REC_DATE = t0.REC_DATE,
STYPE = t0.STYPE,
PART_NO = t2.PART_NO,
LOCATION_AD = (from l in db.LOCATION_MASTER
where l.LOC_CODE = t.LOCATION_AD
select LocName)ToList().FirstorDefault(),
QNTY = t.QNTY,
LOCATION_SD = (from l in db.LOCATION_MASTER
where l.LOC_CODE = t.LOCATION_SD
select LocName).ToList().FirstorDefault(),
REGION_ID = t.REGION_ID
}).Distinct();
See below 2 versions of code and SQL it produces. I want to load preferences but I also want to bring only my user preferences and therefore I use WHERE clause. But as soon as I put it in - I don't get OUTER join anymore. Why?
var query = from p in context.Preferences
join up in context.UserPreferences on p.PreferenceKey equals up.PreferenceKey into outer
from up in outer.DefaultIfEmpty()
select new MobileRESTEntities.UserPreference
{
CreatedOn = (up == null) ? p.CreatedOn : up.CreatedOn,
UpdatedOn = (up == null) ? p.CreatedOn : (up.UpdatedOn ?? up.CreatedOn),
PreferenceId = p.PreferenceId,
Value = (up == null) ? p.ValueDefault : up.Value,
};
With WHERE:
var query = from p in context.Preferences
join up in context.UserPreferences on p.PreferenceKey equals up.PreferenceKey into outer
from up in outer.DefaultIfEmpty()
where up.UserKey.Equals((int)user.ProviderUserKey)
&&
(
(up == null)
||
((up.UpdatedOn > lastSyncOn && up.UpdatedOn != null) || (up.CreatedOn > lastSyncOn))
)
select new MobileRESTEntities.UserPreference
{
CreatedOn = (up == null) ? p.CreatedOn : up.CreatedOn,
UpdatedOn = (up == null) ? p.CreatedOn : (up.UpdatedOn ?? up.CreatedOn),
PreferenceId = p.PreferenceId,
Value = (up == null) ? p.ValueDefault : up.Value,
};
Without WHERE - GOOD
SELECT
[Extent1].[PreferenceKey] AS [PreferenceKey],
CASE WHEN ([Extent2].[UserPreferenceKey] IS NULL) THEN [Extent1].[CreatedOn] ELSE [Extent2].[CreatedOn] END AS [C1],
CASE WHEN ([Extent2].[UserPreferenceKey] IS NULL) THEN [Extent1].[CreatedOn] WHEN ([Extent2].[UpdatedOn] IS NULL) THEN [Extent2].[CreatedOn] ELSE [Extent2].[UpdatedOn] END AS [C2],
[Extent1].[PreferenceId] AS [PreferenceId],
CASE WHEN ([Extent2].[UserPreferenceKey] IS NULL) THEN [Extent1].[ValueDefault] ELSE [Extent2].[Value] END AS [C3]
FROM [dbo].[MBLPreference] AS [Extent1]
LEFT OUTER JOIN [dbo].[MBLUserPreference] AS [Extent2] ON [Extent1].[PreferenceKey] = [Extent2].[PreferenceKey]
With WHERE - BAD - no OUTER JOIN
exec sp_executesql N'SELECT
[Extent1].[PreferenceKey] AS [PreferenceKey],
[Extent2].[CreatedOn] AS [CreatedOn],
CASE WHEN ([Extent2].[UpdatedOn] IS NULL) THEN [Extent2].[CreatedOn] ELSE [Extent2].[UpdatedOn] END AS [C1],
[Extent1].[PreferenceId] AS [PreferenceId],
[Extent2].[Value] AS [Value]
FROM [dbo].[MBLPreference] AS [Extent1]
INNER JOIN [dbo].[MBLUserPreference] AS [Extent2] ON [Extent1].[PreferenceKey] = [Extent2].[PreferenceKey]
WHERE ([Extent2].[UserKey] = #p__linq__0) AND ((1 = 0) OR (([Extent2].[UpdatedOn] > #p__linq__1) AND ([Extent2].[UpdatedOn] IS NOT NULL)) OR ([Extent2].[CreatedOn] > #p__linq__2))',N'#p__linq__0 int,#p__linq__1 datetime2(7),#p__linq__2 datetime2(7)',#p__linq__0=15,#p__linq__1='0001-01-01 00:00:00',#p__linq__2='0001-01-01 00:00:00'
EDIT
Well yes, WHERE Won't work as is but my SQL should looks something like:
SELECT P.*
FROM dbo.MBLPreference P
LEFT OUTER JOIN dbo.MBLUserPreference UP ON P.PreferenceKey = UP.PreferenceKey
AND UP.UserKey = 8 AND UP.CreatedOn > '1-1-1'
How should I write LINQ to achieve this?
ANSWER
This is what I needed to do (Move conditions onto join itself)
var query = from p in context.Preferences
join up in context.UserPreferences
.Where(x =>
x.UserKey.Equals((int)user.ProviderUserKey)
&&
((x.UpdatedOn > lastSyncOn && x.UpdatedOn != null) || (x.CreatedOn > lastSyncOn))
)
on p.PreferenceKey equals up.PreferenceKey into outer
from up in outer.DefaultIfEmpty()
select new MobileRESTEntities.UserPreference
{
CreatedOn = (up == null) ? p.CreatedOn : up.CreatedOn,
UpdatedOn = (up == null) ? p.CreatedOn : (up.UpdatedOn ?? up.CreatedOn),
PreferenceId = p.PreferenceId,
Value = (up == null) ? p.ValueDefault : up.Value,
};
I'm not sure what you are trying to achieve, but I believe you need to move condition in where up :
from p in context.Preferences
join up in context.UserPreferences.Where(x=>x.UserKey ==user.ProviderUserKey &&
(// your other conditions)
)
into outer ....