More efficient Linq expression - c#

I have this Linq Join
var NewQuote = (from qw in Q
join NW in NewNotes on qw.RECID equals NW.RECID into temp
from j in temp
select new Quotes
{
QuoteNumber = qw.QuoteNumber,
CustPartNumber = qw.CustPartNumber,
ITEMGROUPID = qw.ITEMGROUPID,
LotSize = qw.LotSize,
EAU = qw.EAU,
CONTACTPERSONID = qw.CONTACTPERSONID,
QUOTATIONSTATUS = qw.QUOTATIONSTATUS,
QUOTESENTDATE = qw.QUOTESENTDATE,
PricePerPiece = qw.PricePerPiece,
QuoteValue = qw.QuoteValue,
Email = qw.Email,
RECID = qw.RECID,
Notes = j == null ? "" : j.NOTES
}).ToList();
Q is of the Quote class but I need to add the data to the Notes field from NewNotes. Is there a better way to do this than listing every field from the Quote class? If I have to add fields to Quote then I have to document to come to this section of code and update as well.

Why you create new instances of Quotes if you just want to update one property?
var query = from qw in Q join NW in NewNotes
on qw.RECID equals NW.RECID into temp
from j in temp
select new { Quote = qw, Notes = j?.Notes ?? "" };
foreach(var x in query)
{
x.Quote.Notes = x.Notes;
}

Related

Foreach and querys performance improvement issue in C#

I'm having a problem with performance in my code.
The method below is used to create a comparative score of companies from the whole country based some rules:
public List<object> GetCNAEBRCycleChart(int VisitId)
{
List<object> result = new List<object>();
Visit visit = Context.Visit.Find(VisitId);
Company company = visit.Company;
var CNAE = company.MainEconomicCNAE.IdentifyCNAE;
string[] Themes = new string[5];
Themes[0] = "Finance";
Themes[1] = "Market";
Themes[2] = "Organization";
Themes[3] = "Planning";
Themes[4] = "People";
int count = 0;
List<Visit> listVisitCNAECountry = (from vis in Context.Visit
where vis.Company.MainEconomicCNAE.IdentifyCNAE.StartsWith(CNAE)
&& vis.Order == 1
select vis
).ToList();
double[] Values = new double[5];
Values[0] = 0;
Values[1] = 0;
Values[2] = 0;
Values[3] = 0;
Values[4] = 0;
foreach (var vis in listVisitCNAECountry)
{
count = 0;
var visitIdCompany = vis.Id;
var diagnostic = Context.Visit.Find(visitIdCompany).Diagnostic;
if (diagnostic != null)
{
foreach (var itemTheme in Themes)
{
var TemaAux = itemTema;
int QtQuestion = (from itemForm in Context.FormItem
join tipo in Context.FormItemType on itemForm.FormItemTypeId equals tipo.Id
join itemForm2 in Context.FormItem on itemForm.FormItemParentId equals itemForm2.Id
join itemForm3 in Context.FormItem on itemForm2.FormItemParentId equals itemForm3.Id
where itemForm3.Name == TemaAux && tipo.Name == "Pergunta"
select itemForm
).Count();
var sumAnswerCompany = (from alter in Context.Alternative
join itemForm in Context.FormItem on alter.FormItemId equals itemForm.Id
join itemForm2 in Context.FormItem on itemForm.FormItemParentId equals itemForm2.Id
join itemForm3 in Context.FormItem on itemForm2.FormItemParentId equals itemForm3.Id
join answer in Context.Answer on itemForm.Id equals answer.FormItemId
where answer.AlternativeId == alter.Id &&
answer.DiagnosticId == diagnostico.Id && itemForm3.Name == TemaAux
select alter.Value
).AsEnumerable().Sum();
double scoreCompany = //Some calculations
Values[count] += scoreCompany;
count++;
}
}
}
count = 0;
foreach (var val in Values)
{
Values[count] = //more calculations
count++;
}
var model = new { NameCategory = "CNAE in Country", Value1 = Values[0], Value2 = Values[1], Value3 = Values[2], Value4 = Values[3], Value5 = Values[4] };
result.Add(model);
return result;
}
The problem is that, with the actual CNAE, the list listVisitCNAECountry gets 16000+ elements, which make for terrible performance.
In my localhost environment it's taking 30min+ and I don't even know where to begin to actually improve the performance.
The biggest problem is that I really need all those iterations to make the calculations right.
If anyone has any ideas, please, help me.
The first thing to change is:
var sumAnswerCompany = ( /* complex query */
).AsEnumerable().Sum();
This is bad; instead of issuing select sum(...) as a database query, it instead will have to select the column(s) and return all the rows required, which may be a huge amount of bandwidth.
Instead, do the sum at the database and just bring back one number:
var sumAnswerCompany = ( /* complex query */
).Sum();
However, frankly I'd suggest writing the entire thing in raw SQL using joins and grouping from the original data. Sometimes LINQ isn't your best tool.

LINQ: Multiple Join With Max Revision Filter

So I have this line:
var transrevmax = db.TRANSACTs
.Where(x => x.SITE == "1" &&
x.DATE_IN >= dateinchoice &&
x.DATE_OUT <= dateoutchoice)
.GroupBy(x => x.TICKET_NO)
.Select(x => x.OrderByDescending(y => y.REV_NO).FirstOrDefault())
.ToList();
and it returns the exact list of transactions I want the join below to go through to obtain values from...
var exportrecovery = (from trans in transrevmax
join detail in db.DETAILs on new { TICKET_NO = trans.TICKET_NO, REV_NO = trans.REV_NO } equals new { TICKET_NO = detail.TICKET_NO, REV_NO = detail.REV_NO }
join job in db.JOBs on new { JOB_CODE = trans.JOB_CODE, CUST_CODE = trans.CUST_CODE } equals new { JOB_CODE = job.CODE, CUST_CODE = job.CUST_CODE }
join customer in db.CUSTOMERs on trans.CUST_CODE equals customer.CODE
join invoiced in db.INVOICEDs on trans.TICKET_NO equals invoiced.TICKET_NO
where trans.DATE_IN >= dateinchoice && trans.DATE_OUT <= dateoutchoice && trans.STATUS.ToString().Trim() != "V" && trans.STATUS.ToString().Trim() != "E"
select new { ADDRESS = customer.ADDRESS, CITY = customer.CITY, STATE = customer.STATE, ZIP = customer.ZIP, FREIGHT = detail.HAUL_CHGE + detail.FUEL_CHGE, JOB_NAME = job.NAME, HAUL_TAX = detail.HAUL_TAX, INVOICE_NO = invoiced.INVOICE_NO, CUST_NAME = customer.NAME, TAX_CODE = customer.TAX_CODE, MAT_CHGE = detail.MAT_CHGE, MAT_TAX = detail.MAT_TAX, MAT_CODE = detail.MAT_CODE, QTY = detail.QTY, PRICE = detail.PRICE, DATE_MOD = trans.DATE_OUT, REV_NO = trans.REV_NO, SITE = trans.SITE, TICKET_NO = trans.TICKET_NO, CUST_CODE = trans.CUST_CODE, JOB_CODE = trans.JOB_CODE }
).ToList();
... if I run the first line I get the transactions limited to only those with the max revision (what I want), and if I run the join (replacing the "transrevmax" with the table "db.TRANSACTs") I get the right range of ticket numbers, but it includes all revisions. I am stumped as to how I can use the joined tables and get only unique rows according to their (maximum) revision number. When these two are used in conjunction I receive zero rows. Please advise.
Remove the ToList on the transrevmax creation.

How to write Outer Join using LINQ

I am using the below Inner Join to retrive the Data between the two tables, but all data is not getting populated. I tried implementing Outer join by connecting using CCY1== CCY1 and PCODE == PCODE, but no luck.
var q = from g1 in TableCCY1.AsEnumerable()
join g2 in TableCCY2.AsEnumerable()
on g1.Field<string>("CCY1") equals g2.Field<string>("CCY1")
where g1.Field<string>("PCODE") == g2.Field<string>("PCODE")
select new
{
g1currency = g1.Field<string>("CCY1"),
g2currency = g2.Field<string>("CCY1"),
g1code = g1.Field<string>("PCODE"),
g2code = g2.Field<string>("PCODE"),
g1Amt1 = g1.Field<string>("AMT1"),
g2Amt2 = g2.Field<string>("AMT2")
};
Thanks for your help.
For left join you can use this approuch: http://msdn.microsoft.com/en-us/library/vstudio/bb397895.aspx
The code should be:
var q = from g1 in TableCCY1
join g2 in TableCCY2 on g1.CCY1 equals g2.CCY1 && g1.PCODE equals g2.PCODE into TableCCY3
from g3 in TableCCY3.DefaultIfEmpty()
select new
{
g1currency = g1.CCY1,
g2currency = (g3 == null ? String.Empty : g3.CCY1),
g1code = g1.PCODE,
g2code = (g3 == null ? String.Empty : g3.PCODE),
g1Amt1 = g1.AMT1,
g2Amt2 = (g3 == null ? 0 : g3.AMT2)
};
It looks like you just want to union/concat the two tables into one and then just group on those two columns. You're not logically joining the two tables. That actually makes it much easier.
var q = from row in TableCCY1.AsEnumerable().Concat(TableCCY2.AsEnumerable())
group row by new
{
CCY1 = row.Field<string>("CCY1"),
PCode = row.Field<string>("PCODE")
} into matches
select new
{
CCY1 = matches.Key.CCY1,
PCODE = matches.Key.PCode,
Sum = matches.Sum(match => match.Field<decimal?>("AMT2")),
};

Ordinal Position of Element in IENumerable Collection (Linq to XMl )

How do I embed the ordinal number of element as its attribute in this linq query.
var AllSections = from s in xmlDoc.Descendants("section")
select new
{
id = s.Attribute("id").Value,
themeTitle = s.Element("themeTitle").Value,
themeText = s.Element("themeText").Value,
objects = (from a in AllObjects
join b in s.Descendants("object")
on a.Attribute("accessionNumber").Value equals
b.Attribute("accessionNumber").Value
//select a
select new
{
//index = insert ordinal id/index of element
ObjectTitle = a.Element("ObjectTitle").Value,
ObjectText = a.Element("textentry").Value,
}
)
};
You can't easily do it with a query expression - at least not without a horrible side effect. However, you can easily do it with dot notation for either Select or Where. Given that you've got quite a long query expression, it's probably easiest to embed an extra call to where at the start - assuming you do actually want the index of "s" in the original expression:
var AllSections =
from s in xmlDoc.Descendants("section")
select new
{
id = s.Attribute("id").Value,
themeTitle = s.Element("themeTitle").Value,
themeText = s.Element("themeText").Value,
objects = (from a in AllObjects.Select((Item,Index) => new {Item,Index})
join b in s.Item.Descendants("object")
on a.Item.Attribute("accessionNumber").Value equals
b.Attribute("accessionNumber").Value
//select a
select new
{
//index = insert ordinal id/index of element
Index = a.Index,
ObjectTitle = a.Element("ObjectTitle").Value,
ObjectText = a.Element("textentry").Value,
}
)
};
That's assuming you want the index of a within AllObjects.
#Jon Skeet gave you the appropriate overload of Select to use, and here is it in your query:
var AllSections = from s in xmlDoc.Descendants("section")
select new
{
id = s.Attribute("id").Value,
themeTitle = s.Element("themeTitle").Value,
themeText = s.Element("themeText").Value,
objects = (from a in AllObjects
join b in s.Descendants("object")
on a.Attribute("accessionNumber").Value
equals b.Attribute("accessionNumber").Value
select a).Select((a, index) =>
new
{
Index = index,
ObjectTitle = a.Element("ObjectTitle").Value,
ObjectText = a.Element("textentry").Value,
})
};

Linq to SQL With Left Outer Join and Group By With Sum - How To

I'm trying to transform the SQL Query below into Linq to SQL
select Categorias.IdCategoria, Categorias.Nome, SUM(lancamentos.valor)
from lancamentos
left outer join Categorias on Lancamentos.IdCategoria = Categorias.IdCategoria
where Month(DataLancamento) = 11
and Credito = 1
and Lancamentos.Ocultar = 0
group by Categorias.IdCategoria, Categorias.Nome
This is what I've done
from lancamento in Lancamentos
where lancamento.Credito == true
&& lancamento.Ocultar == false
&& lancamento.DataLancamento.Month == 10
join categoria in Categorias on lancamento.IdCategoria equals categoria.IdCategoria into temp
from lancamentoJoinCategoria in temp.DefaultIfEmpty()
group lancamentoJoinCategoria by new { lancamentoJoinCategoria.IdCategoria, lancamentoJoinCategoria.Nome } into x
select new {
IdCategoria = (int?)x.Key.IdCategoria
, Nome = x.Key.Nome
}
How do I add the SUM(lancamentos.valor) to the linq to sql above ?
It will be:
(from lancamento in Lancamentos
join categoria in Categorias on lancamento.IdCategoria equals categoria.IdCategoria into temp
from lancamentoJoinCategoria in temp.DefaultIfEmpty()
where lancamento.Credito == true
&& lancamento.Ocultar == false
&& lancamento.DataLancamento.Month == 10
group lancamento by new { lancamentoJoinCategoria.IdCategoria, lancamentoJoinCategoria.Nome } into x
select new
{
IdCategoria = (int?)x.Key.IdCategoria,
Nome = x.Key.Nome,
sumValor = x.Sum(a=>a.valor)
});
You use the .Sum() method.
Eg;
Public Sub LinqToSqlCount03()
Dim q = (From o In db.Orders _
Select o.Freight).Sum()
Console.WriteLine(q)
End Sub
according to MSDN there is no query expression equivalent to the Sum() operation.
I provided a little sample how you could use the Method Syntax of Sum() in a query.
Some query operations, such as Count
or Max, have no equivalent query
expression clause and must therefore
be expressed as a method call. Method
syntax can be combined with query
syntax in various ways. For more
information, see LINQ Query Syntax versus Method Syntax (C#).
var example = new[]
{
new { Count = 1, Name = "a" }, new { Count = 2, Name = "b" },
new { Count = 2, Name = "c" }, new { Count = 2, Name = "c" }
};
var result = from x in example
select new
{
x.Name,
Sum = (from y in example
where y.Count.Equals(2)
&& y.Name==x.Name
select y.Count).Sum()
};
var distinct = result.Distinct().ToList();

Categories

Resources