Comparing two counts in LINQ - c#

hi have a simple query that compares all sent out requests to those that have been downloaded.
i have a tsql that works perfectly like so:
select case when (select COUNT(*) from FileRecipient where File_ID = 3 and downloaded = 'Y')
= (select COUNT(*) from FileRecipient where File_ID = 3) then 'Y' else 'N' end
but would like to do it in LINQ.
any and all help would be appreciated. i tried the following, but obviously i'm a long way away from getting it right. this just gives me the first of the two counts. do i need to do two separate statements to get the second?
public static bool DownloadedByAll(int fsID)
{
using (SEntities ctx = CommonS.GetSContext())
{
var result = (from fr in ctx.FileRecipients
where fr.File_ID == fsID && fr.downloaded == "Y"
select fr.Recipient_ID).Count();
}
}
or would it just be simpler for me to use tsql within the entity framework for this?

This should get you the result you need
var result = ctx.FileRecipients
.Count(f=>f.File_ID == 3
&& f.downloaded == 'Y') == ctxt.FileRecipients
.Count(f=>f.File_ID == 3);

Related

Sql Query to Linq Query

I have written an sql qyery like
SELECT TOP 1000
[tlotWeight]
,[TEU]
,[SeaAirFlag]
,CASE
WHEN [SeaAirFlag]='SEA' OR [SeaAirFlag]='Sea'
then [TEU]
else [tlotWeight] end as Volume
FROM [LogisticsBI].[dbo].[GoldenVolume]
I want it to convert it to linq c# query,I have tried something like this
(from t in db.GoldenVolumes
select new { Volume=(t.SeaAirFlag=="SEA"|| t.SeaAirFlag=="Sea")?t.TEU: t.tlotWeight)}
).Take(10000).Distinct()
but its showing some syntax error in linqpad
Please help me to correct way in linq to write this query
Well, I see problem with brackets here (opened one time and closed two times):
select new { Volume = (t.SeaAirFlag=="SEA" || t.SeaAirFlag=="Sea") ? t.TEU : t.tlotWeight)}
It looks like this should be either
select new { Volume = ((t.SeaAirFlag=="SEA" || t.SeaAirFlag=="Sea") ? t.TEU: t.tlotWeight)}
or (it's up to you)
select new { Volume = (t.SeaAirFlag=="SEA" || t.SeaAirFlag=="Sea") ? t.TEU: t.tlotWeight }
The error is pretty straightforward you have misarranged your round brackets.
t.tlotWeight)}) is wrong instead it should be t.tlotWeight})
Its better to split them to next lines for more clearity.
var res = (from t in db.GoldenVolumes
select new
{
Volume = (t.SeaAirFlag.ToUpperInvariant().Contains("SEA")) ?
t.TEU : t.tlotWeight
})
.Take(10000)
.Distinct();

how could i handle this linq query and compare it with and int in an if-statement?

i have the following code:
int selectedcourseId = Convert.ToInt32(c1.Text);
var cid = (from g in re.Sections where g.CourseID == selectedcourseId select g.CourseID);
int selectedinstructorid = Convert.ToInt32(c2.Text);
var iid = (from u in re.Sections where u.InstructorID == selectedinstructorid select u.InstructorID);
i want to compare the two (selectedcourseId) with (cid) and (selectedinstructorid) with (iid) in if-statement such as:
if (selectedcourseId = cid && selectedinstructorid = iid)
{
MessageBox.Show("it already exists");
}
i have tried many things that didnt work our because i have limited knowledge.
thank you very much in advance for any comment or answer
You can change your code as: (but it is meaningless for your situation to check this)
if (selectedcourseId == cid.First() && selectedinstructorid == iid.First())
First of all for checking equality in if statement you must use ==, not =. And the second is the IQueryable<T> allows you to execute a query against a specific data source, but it uses deferred execution. For executing it in your case, you can use First().
But, I suggest that you are just learning how to use LINQ and therefore you have written this code.
I don't know what you are trying to achive. But, if you want to search if there is any result with that ID's, the you must use Any():
var result1 = from g in re.Sections where g.CourseID == selectedcourseId select g.CourseID;
var result2 = from u in re.Sections where u.InstructorID == selectedinstructorid select u.InstructorID;
if(result1.Any() && result2.Any()) { ... }
Or, if you want to find if there is any row which has specified CourseID and InstructorID, then you can call one Any():
if(re.Sections.Any(x => x.CourseID == selectedcourseId && x.InstructorID == selectedinstructorid))
{ ... }
Let me try to find the X from this XY-problem. I guess you want to check if there is already a combination of courseid + instructorid. Then use a single query:
var data = from section in re.Sections
where section.InstructorID == selectedinstructorid
&& section.CourseID == selectedcourseId
select section;
if(data.Any())
{
MessageBox.Show("it already exists");
}
You should not do it in two queries, because the two results might be related to two different rows. This would lead to "false positives" when an instructor handles some section, and a course has some instructors, but the two matches do not belong to the same row:
course instructor
------ ----------
100 10
101 15
102 20
If you are looking for a combination (101, 10) it is not enough to see that 100 is present and 10 is present; you need to check that the two belong to the same row in order to consider it a duplicate.
You can fix this by making a "check presence" query, like this:
var existing = re.Sections
.Any(s => s.InstructorID == selectedinstructorid && s.CourseID == selectedcourseId);
if (existing) {
MessageBox.Show("it already exists");
}
if (selectedcourseId = cid && selectedinstructorid = iid)
this will not work, since single '=' is an assignment, not a comparation (which is '==')
also, you can try to do something like this
var cid = (int)((from g in re.Sections where g.CourseID == selectedcourseId select g.CourseID).FirstOrDefault());
so you select the first or default record from your list and cast it to int

Searching for text in a database with Entity Framework

I'm writing a UI that allows a someone to lookup users by their first and/or last name. For example, if you typed in "Mike" for the first name and "Jo" for the last name, it would return "Mike Jones", "Mike Johnson" and "Mike Jobs". I use the following LINQ statement for this search:
var users = (from u in context.TPM_USER
where u.LASTNAME.ToLower().Contains(LastName.ToLower())
&& u.FIRSTNAME.ToLower().Contains(FirstName.ToLower())
select u);
(There may or may not be a better way to do a case-insensitive like clause, but this seems to work)
The problem is if the user types in a first or last name, but then leaves the other field empty. If I type in "Mike" for the first name and leave the Last Name field blank, I want to return all Mikes regardless of their last name. The above query returns no results unless both fields are filled in with at least something.
I tried:
var users = (from u in context.TPM_USER
where (LastName == "" || u.LASTNAME.ToLower().Contains(LastName.ToLower()))
&& (FirstName == "" || u.FIRSTNAME.ToLower().Contains(FirstName.ToLower()))
select u);
However, I still get no results unless both fields are filled out. I've verified under the debugger that LastName == "" is indeed true.
UPDATE:
I did some more debugging and this is actually an Oracle issue. The query being generated is:
--Replaced the field list with * for brevity
SELECT * FROM TPMDBO.TPM_USER "Extent1"
WHERE (('jones' = '') OR ((INSTR(LOWER("Extent1".LASTNAME), LOWER('jones'))) > 0)) AND (('' = '') OR ((INSTR(LOWER("Extent1".FIRSTNAME), LOWER(''))) > 0))
Which at first glance appears to be correct. However, Oracle does not seem to correctly short-circuit the phrase ('' = ''). In fact, if I do:
select * from TPM_USER where '' = ''
I get zero rows. I'm not enough of an Oracle expert to know how this query should be written, but either way it's an Entity Framework dialect bug.
Just add the predicates conditionally:
var users = from u in context.TPM_USER select u;
if (!string.IsNullOrWhiteSpace(FirstName))
users = users.Where(u => u.FIRSTNAME.ToLower().Contains(FirstName.ToLower()));
if (!string.IsNullOrWhiteSpace(LastName))
users = users.Where(u => u.LASTNAME.ToLower().Contains(LastName.ToLower()));
Or only the LASTNAME predicate as conditional one.
Later addition:
An expression like Where(u => u.FIRSTNAME.ToLower()... is better to be avoided. They cause any indexes on FIRSTNAME to be ignored, because the field value is converted first and then compared (see here for more details).
There's a big chance you don't need these lower-case conversions. Check the database collation of the field. If it's case-insensitive (CI), which it probably is, you don't need these conversions.
Are you sure that FirstName and LastName aren't null?
You might try writing it like this instead...
string LowerFirstName = (FirstName + "").ToLower();
string LowerLastName = (LastName + "").ToLower();
var users = (from u in context.TPM_USER
where (LowerLastName == "" || u.LASTNAME.ToLower().Contains(LowerLastName))
&& (LowerFirstName == "" || u.FIRSTNAME.ToLower().Contains(LowerFirstName))
select u);
FYI, if anyone runs into this issue with Oracle, here's a workaround:
var users = (from u in context.TPM_USER
where (LastName == null|| u.LASTNAME.ToLower().Contains(LastName.ToLower()))
&& (FirstName == null || u.FIRSTNAME.ToLower().Contains(FirstName.ToLower()))
select u);
This will get converted to:
'' is null
In SQL, which Oracle interprets as true.
You could simply create a conditional statement around your query:
if (String.IsNullOrWhiteSpace(LastName) && !String.IsNullOrWhiteSpace(FirstName))
{
var users = (from u in context.TPM_USER
where (u.FIRSTNAME.ToLower().Contains(FirstName.ToLower()))
select u);
}
else if (String.IsNullOrWhiteSpace(FirstName) && !String.IsNullOrWhiteSpace(LastName))
{
var users = (from u in context.TPM_USER
where (u.LASTNAME.ToLower().Contains(LastName.ToLower()))
select u);
}
May be you can try checking the length of the search terms to see if it is working in Oracle PL/SQL.
var users = (from u in context.TPM_USER
where ((LastName ?? "").Trim().Length == 0 || u.LASTNAME.ToLower().Contains(LastName.ToLower()))
&& ((FirstName ?? "").Trim().Length == 0 || u.FIRSTNAME.ToLower().Contains(FirstName.ToLower()))
select u);

LINQ-To-SQL - slow query

I'm just wondering if anyone can offer any advice on how to improve my query.
Basically, it'll be merging 2 rows into 1. The only thing the rows will differ by is a 'Type' char column ('S' or 'C') and the Value. What I want to do is select one row, with the 'S' value and the 'C' value, and calculate the difference (S-C).
My query works, but it's pretty slow - it takes around 8 seconds to get the results, which is not ideal for my application. I wish I could change the database structure but I can't sadly!
Here is my query:
var sales = (from cm in dc.ConsignmentMarginBreakdowns
join sl in dc.SageAccounts on new { LegacyID = cm.Customer, Customer = true } equals new { LegacyID = sl.LegacyID, Customer = sl.Customer }
join ss in dc.SageAccounts on sl.ParentAccount equals ss.ID
join vt in dc.VehicleTypes on cm.ConsignmentTripBreakdown.VehicleType.Trim() equals vt.ID.ToString() into vtg
where cm.ConsignmentTripBreakdown.DeliveryDate >= dates.FromDate && cm.ConsignmentTripBreakdown.DeliveryDate <= dates.ToDate
where (customer == null || ss.SageID == customer)
where cm.BreakdownType == 'S'
orderby cm.Depot, cm.TripNumber
select new
{
NTConsignment = cm.NTConsignment,
Trip = cm.ConsignmentTripBreakdown,
LegacyID = cm.LegacyID,
Costs = dc.ConsignmentMarginBreakdowns.Where(a => a.BreakdownType == 'C' && a.NTConsignment == cm.NTConsignment && a.LegacyID == cm.LegacyID && a.TripDate == cm.TripDate && a.Depot == cm.Depot && a.TripNumber == cm.TripNumber).Single().Value,
Sales = cm.Value ?? 0.00m,
Customer = cm.Customer,
SageID = ss.SageID,
CustomerName = ss.ShortName,
FullCustomerName = ss.Name,
Vehicle = cm.ConsignmentTripBreakdown.Vehicle ?? "None",
VehicleType = vtg.FirstOrDefault().VehicleTypeDescription ?? "Subcontractor"
});
A good place to start when optimizing Linq to SQL queries is the SQL Server Profiler. There you can find what SQL code is being generated by Linq to SQL. From there, you can toy around with the linq query to see if you can get it to write a better query. If that doesn't work, you can always write a stored procedure by hand, and then call it from Linq to SQL.
There really isn't enough information supplied to make an informed opinion. For example, how many rows in each of the tables? What does the generated T-SQL look like?
One thing I would suggest first is to take the outputted T-SQL, generate a query plan and look for table or index scans.

Using LINQ to SQL to perform an update/set

So, if I use this query directly or by using db.ExecuteCommand() , everything will work fine;
update Market..Area set EndDate = NULL where ID = 666 and NID =1 and Code = 36003
However, I cant seem to do this in LINQ to SQL, I've tried a few different methods that all seem like they should work, here is an example of one:
var s= db.Area.Single(s => s.ID == 666 && s.Code == 36003 && s.NID == 1);
s.EndDate = null;
db.SubmitChanges();
I dont know what else to try to get this working.
EDIT
I am only trying to edit ONE item
Is there a primary key defined on the Area table?
Linq 2 SQL will not make an update to a table without a primary key defined. (And, as far as I can remember, it will fail silently).
Do you want update more than one item? Even not you can write something like:
IQueryable<Area> iArea =
from s in db.Area
where s.ID == 666 && s.Code == 36003 && s.NID == 1
select s;
iArea.ToList().ForEach(item => { item.EndDate = null; });
db.SubmitChanges();
There is no built in method for doing batch updates. But you can pick some batch extensions from this blog.
Your syntax appears to be correct. The only other thing I can think of which would be causing the failure is if you are trying to do multiple updates within the same data context. Try this:
using (DataContext db = new DataContext())
{
var s = db.Area.Single(s => s.ID == 666 && s.Code == 36003 && s.NID == 1);
s.EndDate = null;
db.SubmitChanges();
}

Categories

Resources