I want to sum price for all products that is in list.
I called a funtion in linQ query.
Total = t0.TbOfferProducts.Sum(x => Customs.CalculateCurrency(x.TbOffer.Price))
But it didnt recognize my function
I wrote another function for linQ, then I called it. But linQ dont recognize my function.
Error:
LINQ to Entities does not recognize the method 'Double Cal_Price(Int32)' method, and this method cannot be translated into a store expression.
I try other versions but none of them didnt work.Help me please.
myList =
(from t0 in DB.TbProducts
where t0.BoActive == true && t0.BoSoftDeleted == false
let price = Cal_Price(t0.InProductId)
select new ProductActivityInfo
{
ID = t0.InProductId,
Name = t0.StProductName,
Code = t0.StProductCode,
Total = price
})
public double Cal_Price(int productId)
{
double total = 0;
using (MyEntityContext DB = new MyEntityContext())
{
var list = DB.TbOfferProducts.Where(x => x.InProductId == productId);
foreach (var item in list)
{
total += Customs.CalculateCurrency(item.TbOffer.Price);
}
}
return total;
}
EF Core is tryng to build SQL but fails when found custom compiled method in query. Correct Total on the client side:
// calculate sum by grouping
var offerPrices =
from op in DB.TbOfferProducts
group op.TbOffer.Price by x.InProductId
select new
{
ProductId = g.Key,
RawPrice = g.Sum()
};
var result =
(from t0 in DB.TbProducts
join op in offerPrices on t0.InProductId equals op.ProductId
where t0.BoActive == true && t0.BoSoftDeleted == false
select new ProductActivityInfo
{
ID = t0.InProductId,
Name = t0.StProductName,
Code = t0.StProductCode,
Total = op.RawPrice
})
.ToList();
// correct Total on the client side
result.ForEach(x => x.Total = Customs.CalculateCurrency(x.Total));
Related
it is possible to perform a LINQ like this SQL:
select invoice.credit, ((sum(detailsInvoice.amount) - sum(detailsInvoice.discount))+ sum(detailsInvoice.tax)) as total
from detailsInvoice
join invoice on detailsInvoice.invoiceID = invoice.ID
where invoice.carga = 1428 and invoice.ID <> 0
group by invoice.credit
I'm getting this result in the SQL
I spend so much time trying to create a LINQ to perform that query, without luck.
you should do something like this, please excuse any typo errors, didn't use a compiler to test it.
var result = db.invoice.Include(x=>x.detailsInvoice).
GroupBy(x=>invoice.credit).
Select(y=> new {
credit = y.Key,
Total = (y.Sum(z=>z.detailsInvoice.amount) - y.Sum(z=>z.detailsInvoice.discount) + y.Sum(z=>detailsInvoice.tax))
});
Hope this helps!
your answer gave me a good idea of what to do.
something important I forgot to mention is the Invoice table and detailsInvoice don't have a relationship.
So this is what I did:
var result = (from _invoice in ruterosContext.Invoice
join _details in ruterosContext.DetailsInvoice
on new { id = _invoice.ID, reference = _invoice.Reference } equals
new { id = _details.invoiceID, reference = _details.Reference }
where _invoice.ID != 0 && _invoice.Carga == 1428
select new {
Credit = _invoice.credit,
amount = _details.amount,
discount = _details.discount,
tax = _details.tax
}).GroupBy(x => x.credit).
Select(y => new { Credit = y.Key,
Total = (y.Sum(z => z.amount) - y.Sum(z => z.discount)) + y.Sum(x => x.tax) });
I've been using linq for a little while now but haven't come across this situation anywhere and my google-fu let me down.
Basically I have two data sets which I did not define and now have to use to return data.
class Header
{
string COMPANY_CODE
string REFERENCE_NBR
string REFERENCE_DUPLICATE
...
}
class Line
{
string COMPANY_CODE
string REFERENCE_NBR
string REFERENCE_DUPLICATE
string STOCK_CODE
string DESCRIPTION
...
}
From a database perspective they join like this
select *
from Header
inner join Line
on header.COMPANY_CODE = Line.COMPANY_CODE
and header.REFERENCE_NBR = Line.REFERNCE_NBR
and header.REFERENCE_DUPLICATE = LINE.REFERENCE_DUPLICATE
and have a 1:Many relationship.
I'm implementing a search feature for a listing that is meant to find any Lines that with a value in STOCK_CODE or DESCRIPTION that matches a given search term. I have seen a couple of methods of joining using a linq query but because of the multiple join conditions I'm a bit lost and have not found any examples of what I'm trying to do.
If I were to write the statement I am trying to get in lamda/linq in SQL it would be:
declare #searchtxt nvarchar(max) = 'test'
Select *
from header h
where exists (
select *
from Line l
where
(
l.stock_code like '%'+#searchtxt+'%'
or l.description like '%'+#searchtxt+'%'
)
and h.COMPANY_CODE = l.COMPANY_CODE
and h.REFERENCE_NBR = l.REFERENCE_NBR
and h.REFERENCE_DUPLICATE = l.REFERENCE_DUPLICATE
)
Any help would be appreciated!
Perhaps, this?
var result = header.Where(h =>
Line.Any(l => (l.stock_code.Contains(searchtxt)
|| l.description.Contains(searchtxt))
&& h.COMPANY_CODE == l.COMPANY_CODE
&& h.REFERENCE_NBR == l.REFERENCE_NBR
&& h.REFERENCE_DUPLICATE == l.REFERENCE_DUPLICATE));
This is a traditional LINQ query for better understanding,
string searchtext = "";
var result = (from h in context.Headers
join l in context.Lines on new { h.COMPANY_CODE, h.REFERENCE_DUPLICATE, h.REFERENCE_NBR } equals new { l.COMPANY_CODE, l.REFERENCE_DUPLICATE, l.REFERENCE_NBR }
where l.STOCK_CODE.Contains(searchtext) || l.DESCRIPTION.Contains(searchtext)
select new
{
COMPANY_CODE = h.COMPANY_CODE,
STOCK_CODE = l.STOCK_CODE
//You can select more fields from "h" and "l"
}).ToList();
Edit:
string searchtext = "";
var result = (from h in context.Headers
join l in context.Lines on new { h.COMPANY_CODE, h.REFERENCE_DUPLICATE, h.REFERENCE_NBR } equals new { l.COMPANY_CODE, l.REFERENCE_DUPLICATE, l.REFERENCE_NBR }
where l.STOCK_CODE.Contains(searchtext) || l.DESCRIPTION.Contains(searchtext)
select h
)
.GroupBy(x => new { x.COMPANY_CODE, x.REFERENCE_DUPLICATE, x.REFERENCE_NBR })
.Select(x => x.First())
.ToList();
db.Header.Join(
db.Line,
h => new { h.COMPANY_CODE, h.REFERENCE_NBR, h.REFERENCE_DUPLICATE },
l => new { l.COMPANY_CODE, l.REFERENCE_NBR, l.REFERENCE_DUPLICATE },
(h, l) => new
{
Header_COMPANY_CODE = h.COMPANY_CODE,
Header_REFERENCE_NBR = h.REFERENCE_NBR,
Header_REFERENCE_DUPLICATE = h.REFERENCE_DUPLICATE,
Line_Company_Code = l.COMPANY_CODE,
Line_REFERENCE_NBR = l.REFERENCE_NBR,
Line_REFERENCE_DUPLICATE = l.REFERENCE_DUPLICATE,
Line_STOCK_CODE = l.STOCK_CODE,
Line_DESCRIPTION = l.DESCRIPTION
}
)
.Where(w => w.Line_STOCK_CODE.Contains(searchText) || w.Line_DESCRIPTION.Contains(searchText))
.ToList();
I am developing a query to grab and join some SQL tables in C# and am having some trouble with grouping and enumerables within the dataset. My query is below. This gives me the data in the format I'm looking for, but it takes way too long when I try to add the enumerated list as indicated below. When I look under the hood I can see it is executing way too many SQL queries. I'd like to get it to just one. Using LinqPad:
void Main()
{
var nightlyRuns = (from a in LoadTestSummaries
join b in LoadTestTestSummaryData
on a.LoadTestRunId equals b.LoadTestRunId
where a.TargetStack == "LoadEnv" &&
a.TestGuid != null &&
a.StartTime != null &&
a.LoadTestRunId != null
orderby a.StartTime
group new {a, b} by new
{
a.TestGuid,
a.Name,
a.Description,
a.StartTime,
a.Duration,
a.NumAgents,
a.NumHosts,
a.PassFail,
a.ResultsFilePath,
a.Splunk
}
into g
let scenarioStart = g.Min(s => s.a.StartTime) ?? g.Min(s => s.a.DateCreated)
let testCases = g.Select(s => s.b)
orderby scenarioStart
select new
{
TestGuid = g.Key.TestGuid,
ScenarioRun = new
{
Name = g.Key.Name,
Description = g.Key.Description,
StartTime = scenarioStart,
Duration = g.Key.Duration,
NumAgents = g.Key.NumAgents,
NumHosts = g.Key.NumHosts,
Result = g.Key.PassFail,
ResultsFilePath = g.Key.ResultsFilePath,
SplunkLink = g.Key.Splunk,
// PROBLEM: Causes too many queries:
TestRuns = from t in testCases select t.TestCaseId
}
}).ToLookup(g => g.TestGuid, g => g.ScenarioRun);
nightlyRuns["ba593f66-695f-4fd1-99c3-71253a2e4981"].Dump();
}
The "TestRuns" line is causing the excessive queries. Any idea what I am doing wrong here?
Thanks for any insight.
Tough answer to test but I think we can avoid the grouping and multiple queries with something like this: (https://msdn.microsoft.com/en-us/library/bb311040.aspx)
var nightlyRuns = (from a in LoadTestSummaries
join b in LoadTestTestSummaryData
on a.LoadTestRunId equals b.LoadTestRunId
where a.TargetStack == "LoadEnv" &&
a.TestGuid != null &&
a.StartTime != null &&
a.LoadTestRunId != null
into testGroup
select new
{
TestGuid = a.TestGuid,
ScenarioRun = new
{
Name = a.TestGuid,
Description = a.Description,
StartTime = a.StartTime ?? a.DateCreated,
Duration = a.Duration,
NumAgents = g.Key.NumAgents,
NumHosts = a.NumHosts,
Result = a.PassFail,
ResultsFilePath = a.ResultsFilePath,
SplunkLink = a.Splunk,
// PROBLEM: Causes too many queries:
TestRuns =testGroup
}
}).OrderBy(x=>x.StartTime).ToLookup(x => x.TestGuid, x => x.ScenarioRun);
nightlyRuns["ba593f66-695f-4fd1-99c3-71253a2e4981"].Dump();
I have a collection of objects where each object also has a collection. Like so:
public class Product
{
public int Id { get; set; }
public List<Tuple<string, double>> Sales { get; set; }
}
I want to run a LINQ query to check if a Product entity exists and, if it does exist, check it's Sales collection to see if a specific string value (from the Tuple) also exists. If it does, I want to return the corresponding double (also from the Tuple).
I know I can do this in a few lines of code, like so:
saleAmount = String.Empty;
product = Model.Products.SingleOrDefault(p => p.Id == product.Id);
if(product != null)
{
productSale = product.Sales.SingleOrDefault(i => i.Item1 == sale.Id);
if(productSale != null)
{
saleAmount = productSale.Item2.ToString();
}
}
Is it possible to do this in one line?
The key here is to not actually materialize your query through the use of SingleOrDefault until you're actually done defining the entirety of it. Use Where instead and then use SingleOrDefault at the very end.
var query = (from product in Model.Products
where product.Id == someProductId
let sale = product.Sales.SingleOrDefault(i => i.Item1 == sale.Id)
where sale != null
select new
{
product,
saleAmount = sale.Item2,
})
.SingleOrDefault();
Is it possible to do it in one line.
I believe you can distill your code to less lines by combining the check into the second sales array such as
var products = Model.Products.Where(p => p.Id == product.Id
&&
p.Sales.Any(i => i.Item1 == sale.Id) );
var saleAmount = (products != null && products.Any())
? products.First().Sales.First().Item2.ToString()
: string.Empty;
Using a Default Value
This solution uses the help from a default faux pre-created Product to be used when one is not found. Using it in the extension method DefaultIfEmpty, that method determines if a empty projection has been returned and in that case it will instead return the faux instance. After that we can safely extract a the value which would be string.empty and assign it to the final string productSale.
Below I use a hardcoded 1.5 as the sale price for easier reading of the example.
// Our default will set saleAmount to string.Empty if nothing is found in Products.
var defProduct = new Product()
{ Id = -1,
Sales = new List<Tuple<string, double>>()
{ new Tuple<string,double>(string.Empty, 0.0) }};
var productSale =
Products.Where(p => p.Id == product.Id && p.Sales.Any (s => s.Item2 == 1.5 ) )
.DefaultIfEmpty( defProduct )
.First ()
.Sales.First()
.Item1;
productSale is string.Empty if no value found or has the actual value to use.
Whole test project in LinqPad which simulates a fail by using 1.5. Use 1.6 to show success.
void Main()
{
var targetSalePrice = 1.5;
var targetProductId = 2;
var Products = new List<Product>() { new Product()
{ Id = 2,
Sales = new List<Tuple<string, double>>()
{ new Tuple<string,double>("actual", 1.6) } }
};
// Our default will set saleAmount to string.Empty if nothing is found in Products.
var defProduct = new Product() { Id = -1, Sales = new List<Tuple<string, double>>()
{ new Tuple<string,double>("faux string.Empty", 0.0) }};
var productSale =
Products.Where(p => p.Id == targetProductId
&& p.Sales.Any (s => s.Item2 == targetSalePrice ) )
.DefaultIfEmpty( defProduct )
.First ()
.Sales.First ()
.Item1;
productSale.Dump(); // outputs the string "faux string.Empty" from the faux default.
}
// Define other methods and classes here
public class Product
{
public int Id { get; set; }
public List<Tuple<string, double>> Sales { get; set; }
}
var list = new List<ListCreaditInBankView>();
var banktemp = m_banksRepository.Banks;
foreach (Bank bank in banktemp)
{
var bankbranchtemp = m_banksRepository.BankBranches.Where(x => x.BankId == bank.Id);
foreach (BankBranch bankBranch in bankbranchtemp)
{
var creditortemp = m_creditorsRepository.Creditors.Where(x => x.BankBranchId == bankBranch.Id);
list.Add(new ListCreaditInBankView(){Bank = bank, Creditors = creditortemp});
}
}
I need get List<ListCreaditInBankView> without these cycles.
I tried, but it only gets a Creditors
var lists = (from bank in banksTemp
let creditorBank = m_creditorsRepository.GetCreditorBank(bank.BankBranches.Select(x => x.Id).ToList())
select new ListCreaditInBankView() {Bank = bank, Creditors = creditorBank}).ToList();
Try the following:
var lists = (from bank in m_banksRepository.Banks
select new ListCreaditInBankView
{
Bank = bank,
Creditors = creditorsRepository.GetCreditorBank(bank.BankBranches
.Select(x => x.Id).ToList())
}).ToList();
Or if you prefer the other style LINQ (method chaining it's called, thanks Numan :)):
var lists = m_banksRepository.Banks
.Select(bank => new ListCreaditInBankView
{
Bank = bank,
Creditors = creditorsRepository.GetCreditorBank(bank.BankBranches
.Select(x => x.Id).ToList())
}).ToList();
If you're using Linq 2 Entity framework, there's another approach you can try.
http://msdn.microsoft.com/en-us/library/bb896272.aspx
You just need to be sure, that you've set your tables and keys in your database correctly (or at least mapping in the generated model), otherwise it won't work.