Simple math question with LinQ, simple Join query, Nulls, etc - linq-to-sql

I have 2 tables
1. Client
2. Operations
Operations can result in: Credits or Debits ('C' or 'D' in a char field) along with date and ammount fields.
I must calculate the balance for each client's account using linQ... The result should also show balance 0 for clients whom didn't make operations yet
I have the following function with linQ statement, but I know it could be done in a better and quicker, shorter way, right? Which will be?
public static double getBalance(ref ClasesDeDatosDataContext xDC, string SSN,
int xidClient)
{
var cDebits =
from ops in xDC.Operations
where (ops.idClient == xidClient) && (ops.OperationCode == 'D')
select ops.Ammount;
var cCredits =
from ops in xDC.Operations
where (ops.idClient == xidClient) && (ops.OperationCode == 'C')
select ops.Ammount;
return (double)(cCredits.Sum() - cDebits.Sum());
}
Thanks !!!

I don't know if the LINQ-to-SQL engine can handle the expression, but something like this should be possible:
return (
from ops in xDC.Operations
where ops.idClient == xidClient
select ops.operationCode == 'C' ? ops.Amount : -ops.Amount
).Sum(a => a);
Or perhaps:
return (
from ops in xDC.Operations
where ops.idClient == xidClient
select new { Sign = ops.operationCode == 'C' ? 1.0 : -1.0, Amount = ops.Amount }
).Sum(o => o.Sign * o.Amount);
If the collection is empty, the Sum method returns zero, so that takes care of clients without transactions.
Edit:
Corrected spelling in query: Ampont -> Amount

Related

I wan to check that is my sql command containing the inputted data or not

I have two rounds "first and knock-out".Only the 4 team can go to knock-out round if they got the highest point on first round. Now firstly, I want to select that 4 team from first round and then check whether the inputted team is on the selected 4 team or not. Take a look to my code(So far i tried)
[In this image the two teams are marked should be exclude but when i giving condition it doesn't exclude those two teams]
$matches= new Match();
$matches->team1 = $request->input('team1');
$matches->team2 = $request->input('team2');
$ko = DB::select('SELECT * FROM points WHERE round="first" ORDER BY points DESC , run_rate DESC LIMIT 4');
if($ko == $matches->team1 || $ko == $matches->team2) {
$matches->round = "ko";
} else {
$matches->round = "first";
}
Screenshot of $kos after update.
First of all, $ko doesn't contain the results of the query until you pass it a closure, in this case ->first().
$ko = DB::select('SELECT * FROM points WHERE round="first" ORDER BY points DESC , run_rate DESC LIMIT 4')->first();
Next, you need to compare the value of $ko->team to $matches->team1 or $matches->team2:
if($ko->team == $matches->team1 || $ko->team == $matches->team2) {
...
}
Lastly, some clean up. The DB query can be simplified to use Eloquent syntax, instead of a raw SELECT:
$ko = DB::table("points")
->where("round", "=", "first")
->orderBy("points", "DESC")
->orderBy("run_rate", "DESC")
// ->limit(4) // Removing this; incompatible with `->first()`
->first();
There's another logic error; if you need to limit(4), then you can't use ->first(), you'd have to use ->get(), which then creates a Collection, which can't be compared to $matches unless you loop:
$kos = DB::table("points")...->get();
$matches->round = "first";
foreach($kos AS $ko){
if($ko->team == $matches->team1 || $ko->team == $matches->team2) {
$matches->round = "ko";
break;
}
}
All in all, you need to reexamine what you're trying to do and read up on the Eloquent syntax, how to execute queries and return results, how to loop, access properties and compare those results, etc.
Edit: Since you're looping and comparing, set the default value of $matches->round to "first", then, while looping, if the compare condition is true, override $matches->round to "ko" and break out of the loop.

LINQ to SQL generates negative conditions in WHERE clause

I am using LINQ to SQL to retrieve data, using boolean conditions (BIT columns in SQL). My LINQ query looks something like this:
var query = from r in db.Requests
select r;
query = query.Where(r => r.Completed == someBooleanVal);
query = query.Where(r => r.Cancelled == someOtherBool);
return query.ToList();
The 'Where()' gets applied in a different method, that's why I'm putting it in separately.
When the boolean values are given as false, the generated SQL looks something like this:
SELECT [t0].[col1], [t0].[col2], [t0].[col3], [t0].[etc]
FROM [dbo].[Requests] AS [t0]
WHERE (NOT(([t0].[Cancelled]) = 1) AND (NOT(([t0].[Completed]) = 1)
in stead of what I would use:
WHERE [t0].[Cancelled] = 0 AND [t0].[Completed] = 0
This runs very, very slowly. I strongly suspect that it is because of the negative conditions on the boolean values it generated (all the selected columns are covered by an index, and the two columns in the where clause have a separate index on them).
Why is it generating negative conditions? How can I fix it?
var query =
from r in db.Requests.Where(r => r.Completed == someBooleanVal && r.Cancelled == someOtherBool)
select r;
return query.ToList();
Hope it can help you and have a nice day.

query result what should i use Count() or Any()

I am checking login of a user by this repository method,
public bool getLoginStatus(string emailId, string password)
{
var query = from r in taxidb.Registrations
where (r.EmailId == emailId && r.Password==password)
select r;
if (query.Count() != 0)
{
return true;
}
return false;
}
I saw in one of the previous questions !query.Any() would be faster... Which should i use? Any suggestion....
The sql generated will be different between the two calls. You can check by setting your context.Log property to Console.Out or something.
Here's what it will be:
SELECT COUNT(*) AS [value]
FROM [dbo].[Registrations] AS [t0]
WHERE [t0].[EmailId] = #p0 and [t0].Password = #p1
SELECT
(CASE
WHEN EXISTS(
SELECT NULL AS [EMPTY]
FROM [dbo].[Registrations] AS [t0]
WHERE [t0].[EmailId] = #p0 and [t0].Password = #p1
) THEN 1
ELSE 0
END) AS [value]
In this case, I doubt it will make any difference because EmailID is probably a unique index so there can only be 1 result. In another case where count can be > 1, Any would be preferable because the second query allows sql server to short circuit the search since it only needs to find one to prove that any exist.
You could express it quite a bit shorter like this:
return taxidb.Registrations.Any(r => r.EmailId == emailId && r.Password==password);

Using one LINQ statement with different parameters

I have a pretty complex linq statement I need to access for different methods. Each of these methods may need to see the resulting data with different parameters. For one method it may be a project code, for another it may be language. The statement is pretty much the same it's just the where part which changes.
I have not been able to figure out how to use different where statements without duplicating the entire linq statement, and that just isn't dry enough for me.
For example (greatly simplified):
var r = from c in customer
where c.name == "some name"
// or it may be
var r = from c in customer
where c.customerId == 8
Is there a way to have both of these in the same statement so I can use one or the other based on what I am doing? I tried an if statement to use one of the where statements or the other, and that didn't go over very well.
You can do it like this:
var r = from c in customer
select c;
if (CustomerName != null)
r = r.Where(c => c.name == CustomerName);
if (CustomerID != null)
r = r.Where(c => c.customerId == CustomerID);
You could make these else if if only one should apply, in my example any criteria that wasn't null would be applied to the query to filter on.
what about something like this?
var useIdForFiltering = false;
var r = from c in customer
where (useIdForFiltering && c.customerId == 8) || (c.name == "some name")
You can pass in a Func delegate to your function (the Where clause takes a Func delegate with a boolean return type). Then use this delegate in the Where clause.

LINQ to SQL - nullable types in where clause

I have a table with a column that has null values... when I try to query for records where that column IS NULL:
THIS WORKS:
var list = from mt in db.MY_TABLE
where mt.PARENT_KEY == null
select new { mt.NAME };
THIS DOES NOT:
int? id = null;
var list = from mt in db.MY_TABLE
where mt.PARENT_KEY == id
select new { mt.NAME };
Why?
after some more googling, I found the answer:
ref #1
ref #2
int? id = null;
var list = from mt in db.MY_TABLE
where object.Equals(mt.PARENT_KEY, id) //use object.Equals for nullable field
select new { mt.NAME };
This LINQ renders to SQL as follows:
((mt.PARENT_KEY IS NULL) AND (#id IS NULL))
OR ((mt.PARENT_KEY IS NOT NULL) AND (#id IS NOT NULL) AND (mt.PARENT_KEY = #id))
One possibility - if mt.PARENT_KEY is of some other type (e.g. long?) then there will be conversions involved.
It would help if you could show the types involved and the query generated in each case.
EDIT: I think I have an idea...
It could be because SQL and C# have different ideas of what equality means when it comes to null. Try this:
where (mt.PARENT_KEY == id) || (mt.PARENT_KEY == null && id == null)
If this is the case then it's a pretty ugly corner case, but I can understand why it's done that way... if the generated SQL is just using
WHERE PARENT_KEY = #value
then that won't work when value is null - it needs:
WHERE (PARENT_KEY = #value) OR (PARENT_KEY IS NULL AND #value IS NULL)
which is what the latter LINQ query should generate.
Out of interest, why are you selecting with
select new { mt.NAME }
instead of just
select mt.NAME
?) Why would you want a sequence of anonymous types instead of a sequence of strings (or whatever type NAME is?
It's definitely a matter of C# and SQL having different notions of how to compare nulls - the question has been addressed here before:
Compare nullable types in Linq to Sql