Linq C#, less performance with join vs multiple lookups - c#

I have an older version of code that was doing multiple lookup. I needed some additional fields so instead i rewrote it to do a couple joins and return everything i needed at once. I imagined this would have better performance, but when testing with a stopwatch this was not the case and quite slower. Am i inadvertently doing something wrong with my query?
Old Code
// ===============================old
var watchOld = System.Diagnostics.Stopwatch.StartNew();
var def = context.FDataMLBPlayers.Where(d => d.Status.Trim().ToLower().Equals("active") && d.Position.Trim().ToLower().Equals(position.ToLower())).OrderBy(d => d.Team);
foreach (var dd in def)
{
bool addPlayer = false;
foreach (var tm in teams)
{
if (tm.Trim().Equals(dd.Team.Trim()))
{
addPlayer = true;
break;
}
}
if (!addPlayer) continue;
Player player = new Player();
player.Name = dd.FirstName.Trim() + " " + dd.LastName.Trim();
player.LastName = dd.LastName.Trim();
player.Number = dd.Jersey.HasValue ? dd.Jersey.Value : 0;
player.PlayerID = dd.PlayerID;
player.Points = 0;
player.Position = (dd.Position == null) ? "" : dd.Position.Trim();
player.Score = 0;
player.Status = "Active";//DOROC dd.CurrentStatus;
player.Team = dd.Team.Trim();
htop ht = GetOpposingTeam(dd.Team.Trim()); //another lookup
player.OpposingTeam = ht.OpposingTeam;
player.PhotoUrl = dd.PhotoUrl.Trim();
player.IsHomeTeam = ht.IsHomeTeam;
if (dd.Position != null)
{
list.Add(player);
}
}
watchOld.Stop();
var oldTime = watchOld.ElapsedMilliseconds; // 227 ms
New Code
// ========================================== new
var watchNew = System.Diagnostics.Stopwatch.StartNew();
var def2 = (from p in context.FDataMLBPlayers
join g in context.FDataMLBPlayerGames on p.PlayerID equals g.PlayerID
join t in context.FDataMLBTeams on g.OpponentID equals t.TeamID
where p.Status.Trim().ToLower().Equals("active")
&& p.Position.Trim().ToLower().Equals(position.ToLower())
&& teams.Contains(p.Team)
group new { p, g, t }
by new { p.PlayerID } into pgt
let fod = pgt.FirstOrDefault()
select new Player
{
DateTime = fod.g.DateTime.Value,
IsHomeTeam = fod.g.HomeOrAway.ToLower().Equals("home") ? true : false,
LastName = fod.p.LastName,
Name = fod.p.FirstName.Trim() + " " + fod.p.LastName.Trim(),
Number = fod.p.Jersey.HasValue ? fod.p.Jersey.Value : 0,
OpposingTeam = fod.t.Name,
PhotoUrl = fod.p.PhotoUrl,
PlayerID = fod.p.PlayerID,
Points = 0,
Position = fod.p.Position,
Score = 0,
Started = fod.g.Started.Value.Equals(1) ? true : false,
Status = fod.p.Status,
Team = fod.p.Team,
}
).ToList();
list = def2;
watchNew.Stop();
var newTime = watchNew.ElapsedMilliseconds; // 399 ms

Related

Function in linq select

I have this error :
LINQ to Entities does not recognize the method: GetDebitOuCredit
When I run this:
using (SXEntities db = new SXEntities())
{
result = from ecriture in db.Ecrits
join compte in db.Comptes on ecriture.Compte equals compte.Compte1
join societe in db.Societes on ecriture.Societe equals societe.Societe1
select new EcritDTO
{
LibelleElement = compte.Libelle,
LienGED = string.Empty, // WIP
Compte = ecriture.Compte,
Collectif = ecriture.RacColtif,
Date = ecriture.DateC,
Journal = ecriture.Journal,
Piece = ecriture.Piece,
CodeOperation = ecriture.CodeOpe,
Libelle = ecriture.Libelle,
ReferenceDocument = ecriture.DocuRef,
// Error just below
Debit = GetDebitOuCredit("Debit", societe.DCMoins, ecriture.MtDeb, ecriture.MtCre),
};
}
I cannot use this function:
public double GetDebitOuCredit(string choix, string dcMoins, double? montantDebit, double? montantCredit)
{
double debit = 0;
double credit = 0;
bool isMontantNegatif = string.IsNullOrEmpty(dcMoins) && dcMoins == "1";
if(montantDebit != null && montantDebit != 0 && montantCredit != null && montantCredit != 0)
{
double difference = (double)montantDebit - (double)montantCredit;
if(difference < 0 && isMontantNegatif)
{
debit = 0;
credit = Math.Abs(difference);
}
else
{
debit = difference;
credit = 0;
}
}
return choix == "Debit" ? debit : credit;
}
My question: How can I transform my function GetDebitOrCredit to LINQ expression?
Actually if it is final projection, you don't have to translate this function.
If not, you have to use third party extensions for that:
https://github.com/hazzik/DelegateDecompiler
https://github.com/axelheer/nein-linq/
Never tried DelegateDecompiler, so will show sample using NeinLinq
[InjectLambda]
public double GetDebitOuCredit(string choix, string dcMoins, double? montantDebit, double? montantCredit)
{
_getDebitOuCreditFunc ??= GetDebitOuCredit().Compile();
return _getDebitOuCreditFunc(choix, dcMoins, montantDebit, montantCredit);
}
static Func<string, string, double?, double?, double> _getDebitOuCreditFunc;
public static Expression<Func<string, string, double?, double?, double>> GetDebitOuCredit()
{
return (choix, dcMoins, montantDebit, montantCredit) =>
montantDebit != null && montantDebit != 0 && montantCredit != null && montantCredit != 0)
? ((double)montantDebit < (double)montantCredit) && dcMoins == "1"
? choix == "Debit" ? 0 : (double)montantCredit) - (double)montantDebit
: choix == "Debit" ? (double)montantDebit - (double)montantCredit) : 0
: 0;
}
Then you can use your function in LINQ queries after ToInjectable() call.
result = from ecriture in db.Ecrits.ToInjectable()
join compte in db.Comptes on ecriture.Compte equals compte.Compte1
...
Perhaps you forgot to actually run the query and it's running later when you try to apply some other operation to it. Try
using (SXEntities db = new SXEntities())
{
var q = from ecriture in db.Ecrits
join compte in db.Comptes on ecriture.Compte equals compte.Compte1
join societe in db.Societes on ecriture.Societe equals societe.Societe1
select new EcritDTO
{
LibelleElement = compte.Libelle,
LienGED = string.Empty, // WIP
Compte = ecriture.Compte,
Collectif = ecriture.RacColtif,
Date = ecriture.DateC,
Journal = ecriture.Journal,
Piece = ecriture.Piece,
CodeOperation = ecriture.CodeOpe,
Libelle = ecriture.Libelle,
ReferenceDocument = ecriture.DocuRef,
// Error just below
Debit = GetDebitOuCredit("Debit", societe.DCMoins, ecriture.MtDeb, ecriture.MtCre),
};
result = q.ToList();
}
Also you should be able to remove the joins and do something like:
using (SXEntities db = new SXEntities())
{
var q = from ecriture in db.Ecrits
select new EcritDTO
{
LibelleElement = ecriture.Compte.Libelle,
LienGED = string.Empty, // WIP
Compte = ecriture.Compte,
Collectif = ecriture.RacColtif,
Date = ecriture.DateC,
Journal = ecriture.Journal,
Piece = ecriture.Piece,
CodeOperation = ecriture.CodeOpe,
Libelle = ecriture.Libelle,
ReferenceDocument = ecriture.DocuRef,
// Error just below
Debit = GetDebitOuCredit("Debit", ecriture.Societe.DCMoins, ecriture.MtDeb, ecriture.MtCre),
};
result = q.ToList();
}
Assuming your model has proper navigation properties.

How to solve System.OutofMemoryException in linq using C#?

I have two list. First list consist 70000 row and second list consist 20000 row. After join two list 'System.OutofMemoryException' error occour.
Here my code:
var resultx12 = (from a in resultx
join b in resultx1
on new { stdtab = a.sectionStd.Trim(), stdli = a.liStd.Trim() }
equals new { stdtab = b.sectionStd.Trim(), stdli = b.liStd.Trim() }
into tempBrokerBogeyMapped
from x in tempBrokerBogeyMapped.DefaultIfEmpty()
.Skip(totalFetched)
.Take(1000)
select new LiReportCompareContainer
{
Origin = Origin,
Broker = data.Broker,
FormulaStd = a.FormulaStd,
Formula = x == null ? "" : String.IsNullOrEmpty(x.Formula) ? "" : x.Formula.Trim(),
Group = a.Group,
liBroker = a.liBroker,
Link = a.Link,
liStd = a.liStd,
Period1 = a.Period1,
Period1Value = a.Period1Value,
Period2 = a.Period2,
Period2Value = a.Period2Value,
Period3 = a.Period3,
Period3Value = a.Period3Value,
sectionBroker = a.sectionBroker,
sectionStd = a.sectionStd,
Unit = a.Unit,
}).ToList();
System.OutofMemoryException error showing.

I want to create a jquery for conversion of gold to amount and vice versa

Problem Description : I want to create jquery method from where i can convert gold weight to amount by multiplying it from gold rate f.e 50*2000=100000 and vice versa also that is Amount to Gold by dividing it from gold rate f.e 100000/2000=50
Amount=GoldWeight*GoldRate; // TOP DOWN APPROACH
GoldWeight=Amount/GoldRate; // BOTTOM UP APPROACH
But at the same if all textbox have values it should convert gold if we change amount and also amount if we change in gold value....Please help me in this..
This is the Answer
$(document).ready(function() {
$('#txtGoldConverted').focusin(function() {
var r = $('#txtAmount').val();
var q = $('#txtGoldRate').val();
if (r != "" && q != "") {
var p = r / q;
var res = p.toFixed(3);
var resRound = (Math.round(res * 100)) / 100;
$('#txtGoldConverted').val(resRound);
}
});
$('#txtGoldConverted').focusout(function() {
var p = $('#txtGoldConverted').val();
var q = $('#txtGoldRate').val();
if (p != "" && q != "") {
var r = p * q;
$('#txtAmount').val(r);
}
});
$('#txtGoldRate').focusout(function() {
var p = $('#txtGoldConverted').val();
var q = $('#txtGoldRate').val();
var r = p * q;
$('#txtamount').val(r);
});
$('#txtAmount').focusin(function() {
var p = $('#txtGoldConverted').val();
var q = $('#txtGoldRate').val();
if (p != "" && q != "") {
var r = p * q;
$('#txtAmount').val(r);
}
});
$('#txtAmount').focusout(function() {
var r = $('#txtAmount').val();
var q = $('#txtGoldRate').val();
if (r != "" && q != "") {
var p = r / q;
var res = p.toFixed(3);
var resRound = (Math.round(res * 100)) / 100;
$('#txtGoldConverted').val(res);
}
});
});
You need to use focusout() function on your both Textboxes inorder to Change one Value Based on Other
Example
$('#goldbox').focusout(function(){
var newamount;
//calculate money value based on gold
$('#moneybox').val(newamount);
});

Timeout while grouping

I have a report screen where I do group by over 200 MB of data in DB and sometimes i get timeout, sometimes runs to completion.
How can i optimize it or make it faster?
Below is the code I have :
public ActionResult CleanReport()
{
var count = _db.Surveys.AsNoTracking().Count();
var result = _db.Surveys.AsNoTracking().GroupBy(x => x.Clean).Select(group => new { Clean = group.Key, Count = group.Count() });
var items = new List<PieChartModel>();
foreach (var item in result)
{
if (item.Clean.HasValue == false)
{
continue;
}
var chartModel = new PieChartModel();
if (item.Clean == Clean.IdareEder)
{
chartModel.color = "#F7464A";
chartModel.highlight = "#FF5A5E";
}
if (item.Clean == Clean.Iyiydi)
{
chartModel.color = "#46BFBD";
chartModel.highlight = "#5AD3D1";
}
if (item.Clean == Clean.Kötüydü)
{
chartModel.color = "#642EFE";
chartModel.highlight = "#642EFE";
}
if (item.Clean == Clean.CevapYok)
{
chartModel.color = "#FFCC00";
chartModel.highlight = "#FFCC66";
}
chartModel.label = item.Clean.Value.DisplayName();
double per = (item.Count * 100.0) / count;
chartModel.value = (int)Math.Round(per);
items.Add(chartModel);
}
return Json(items, JsonRequestBehavior.AllowGet);
}

Randomly Selected Data from Database with Constraints

I have created a MySQL Database with a vast number of products and their cost. I utilize EF6 to wrap the database.
Based on the given input, I need to generate at random, a correct selection that meets the described criteria.
For example:
10 Items, Total Value $25
I am at a loss as how to properly go about iterating through the database to produce the required results.
What I am currently doing seems terribly inefficent:
using (var db = new Database())
{
var packageSelected = false;
var random = new Random();
var minItemId = (from d in db.products select d.id).Min();
var maxItemId = (from d in db.products select d.id).Max();
var timer = new Stopwatch();
timer.Start();
Console.WriteLine("Trying to make package...");
while (!packageSelected)
{
var currentItems = new List<int>();
for (var i = 0; i <= 9; i++)
{
var randomItem = random.Next(minItemId, maxItemId);
currentItems.Add(randomItem);
}
decimal? packageValue = 0;
currentItems.ForEach(o =>
{
var firstOrDefault = db.products.FirstOrDefault(s => s.id == o);
if (firstOrDefault != null)
{
var value = firstOrDefault.MSRP;
packageValue += value;
}
});
if (!(packageValue >= 25) || !(packageValue <= 26)) continue;
packageSelected = true;
timer.Stop();
Console.WriteLine("Took {0} seconds.", timer.Elapsed.TotalSeconds);
currentItems.ForEach(o =>
{
var firstOrDefault = db.products.FirstOrDefault(s => s.id == o);
if (firstOrDefault != null)
Console.WriteLine("Item: {0} - Price: ${1}", firstOrDefault.DESCRIPTION,
firstOrDefault.MSRP);
});
}
}
What about something like this:
public virtual TEntity GetRandom()
{
return DBSet.OrderBy(r => Guid.NewGuid()).Take(1).First();
}
public List<TEntity> Random(int amount, int maxprice)
{
var list = new List<TEntity>();
var tempPrice = 0;
for (int i = 0 ; i < amount; i++)
{
var element = GetRandom();
tempPrice += element.Price;
if (tempPrice > maxprice)
{
return list;
}
list.Add(element);
}
return list;
}
hope this helps
EDIT: If the maxprice is reached before the required amount of elements, the for-loop will stop and you won't get the full amount of elements.

Categories

Resources