Converting a given SQL Query to LINQ - c#

I'm new to creating a LINQ so I'm having a hard time converting this SQL query into LINQ. Can someone help me please
SELECT *
FROM myTable1
WHERE (Flag1 <> 'X' OR Flag2 != 'X' OR Flag3 != 'X')
AND number IN (SELECT externalid FROM db2.myTable2 WHERE item = 6)
This is what I've already tried
//get external id
var externalNumber = from s in db2.myTable2
where s.item == 6
select externalid;
var query = from f in db1.myTable1
where (f.Flag1 != "X" || f.Flag2 != "X" || f.Flag3 != "X") && f.number == externalNumber
select f;

Direct translation is:
var query =
from f in db.myTable1
where (f.Flag1 != "X" || f.Flag2 != "X" || f.Flag3 !="X") &&
db.myTable2.Where(s => s.item == 6).Select(s => s.externalId).Contains(f.number)
select f;
IN in LINQ has analogue Contains

var externalid = db2.myTable2Repository.FirstOrDefault(f=>f.item == 2).Result.externalid;
This first code return externalid from db2.myTable2
var data = myTable1Repository.GetAll().Where(w=>(w.Flag1 != X || w.Flag2 != X || w.Flag3 != X) && w.number == externalid)
Second code:
GetAll() is a method of your repository (or baseRepository) and Where() is part of linq
First part of where -> (w.Flag1 != X || w.Flag2 != X || w.Flag3 != X) is self explain
Second part -> (&& w.number == externalid):
I'm not very good with sql so this second part may have got it wrong ,but if I understand correctly, you check the "number" property against a value from another table, so you can just look up this value and store it in a variable.
I'm sorry if I misunderstood the second part in the "and number in", I'm really not good at SQL, and for my bad English too.
If you have any questions we are here :D

Try the Below code:
DatabaseEntities dc=new DatabaseEntities();
var res=dc.myTable1.Where(s=>s.Flag <> 'X' || Flag2 !='X' || Flag3 !='X' && s.number.Contains(dc.myTable2.Where(m=>m.item==6)))

Related

How can I pull a repeated where clause expression from linq into a function?

I have a large project where I have dozens of linq statements where I am looking for a matching record by checking several fields to see if they match or both field and compared field are null.
var testRecord = new { firstField = "bob", secondField = (string)null, thirdField = "ross" };
var matchRecord = dataContext.RecordsTable.FirstOrDefault(vi =>
(vi.first == testRecord.firstField || ((vi.first == null || vi.first == string.Empty) && testRecord.firstField == null))
&& (vi.second == testRecord.secondField || ((vi.second == null || vi.second == string.Empty) && testRecord.secondField == null))
&& (vi.third == testRecord.thirdField || ((vi.third == null || vi.third == string.Empty) && testRecord.thirdField == null)));
//do stuff with matchRecord
Ideally I would replace all that duplicated code (used around 50 times across the system I'm working on) with something like the following
Expression<Func<string, string, bool>> MatchesOrBothNull = (infoItem, matchItem) => (
infoItem == matchItem || ((infoItem == null || infoItem == string.Empty) && matchItem == null));
var matchRecord = dataContext.RecordsTable.FirstOrDefault(vi =>
MatchesOrBothNull(vi.first, testRecord.firstField)
&& MatchesOrBothNull(vi.second, testRecord.secondField)
&& MatchesOrBothNull(vi.third, testRecord.thirdField));
//do stuff with matchRecord
My question is two-fold: First, is there a matched or both null function already available? (I've looked without luck).
Second, the code block above compiles, but throws a "no supported translation to sql" error, is there a way to have a function in the where clause? I know that there is a translation because it works if I don't pull it into the function. How can I get that translated?
First of all you can check whether string is null or empty with single code which is called : String.IsNullOrEmpty(vi.first). You need a method like this one :
public bool MatchesOrBothNull(string first,string second){
if(first==second||String.IsNullOrEmpty(first)||String.IsNullOrEmpty(second))
return true;
else return false;
}
You can use it in where clause
var matchRecord = dataContext.RecordsTable.Where(vi =>
MatchesOrBothNull(vi.first, testRecord.firstField)
&& MatchesOrBothNull(vi.second, testRecord.secondField)
&& MatchesOrBothNull(vi.third, testRecord.thirdField)
).FirstOrDefault();

Entity Framework: Count() very slow on large DbSet and complex WHERE clause

I need to perform a count operation on this Entity Framework (EF6) data set using a relatively complex expression as a WHERE clause and expecting it to return about 100k records.
The count operation is obviously where records are materialized and therefore the slowest of operations to take place. The count operation is taking about 10 seconds in our production environment which is unacceptable.
Note that the operation is performed on the DbSet directly (db being the Context class), so no lazy loading should be taking place.
How can I further optimize this query in order to speed up the process?
The main use case is displaying an index page with multiple filter criteria but the the function is also used for writing generic queries to the ParcelOrderstable as required for other operations in the service classes which might be a bad idea resulting in very complex queries resulting from laziness and might potentially be a future problem.
The count is later used for pagination, and a much smaller number of records (e.g. 500) is actually displayed. This is a database-first project using SQL Server.
ParcelOrderSearchModel is a C#-class that serves to encapsualte query parameters and is used exclusively by service classes in order to call the GetMatchingOrdersfunction.
Note that on the majority of calls, the majority of the parameters of ParcelOrderSearchModel will be null.
public List<ParcelOrderDto> GetMatchingOrders(ParcelOrderSearchModel searchModel)
{
// cryptic id known --> allow public access without login
if (String.IsNullOrEmpty(searchModel.KeyApplicationUserId) && searchModel.ExactKey_CrypticID == null)
throw new UnableToCheckPrivilegesException();
Func<ParcelOrder, bool> userPrivilegeValidation = (x => false);
if (searchModel.ExactKey_CrypticID != null)
{
userPrivilegeValidation = (x => true);
}
else if (searchModel.KeyApplicationUserId != null)
userPrivilegeValidation = privilegeService.UserPrivilegeValdationExpression(searchModel.KeyApplicationUserId);
var criteriaMatchValidation = CriteriaMatchValidationExpression(searchModel);
var parcelOrdersWithNoteHistoryPoints = db.HistoryPoint.Where(hp => hp.Type == (int)HistoryPointType.Note)
.Select(hp => hp.ParcelOrderID)
.Distinct();
Func<ParcelOrder, bool> completeExpression = order => userPrivilegeValidation(order) && criteriaMatchValidation(order);
searchModel.PaginationTotalCount = db.ParcelOrder.Count(completeExpression);
// todo: use this count for pagination
}
public Func<ParcelOrder, bool> CriteriaMatchValidationExpression(ParcelOrderSearchModel searchModel)
{
Func<ParcelOrder, bool> expression =
po => po.ID == 1;
expression =
po =>
(searchModel.KeyUploadID == null || po.UploadID == searchModel.KeyUploadID)
&& (searchModel.KeyCustomerID == null || po.CustomerID == searchModel.KeyCustomerID)
&& (searchModel.KeyContainingVendorProvidedId == null || (po.VendorProvidedID != null && searchModel.KeyContainingVendorProvidedId.Contains(po.VendorProvidedID)))
&& (searchModel.ExactKeyReferenceNumber == null || (po.CustomerID + "-" + po.ReferenceNumber) == searchModel.ExactKeyReferenceNumber)
&& (searchModel.ExactKey_CrypticID == null || po.CrypticID == searchModel.ExactKey_CrypticID)
&& (searchModel.ContainsKey_ReferenceNumber == null || (po.CustomerID + "-" + po.ReferenceNumber).Contains(searchModel.ContainsKey_ReferenceNumber))
&& (searchModel.OrKey_Referencenumber_ConsignmentID == null ||
((po.CustomerID + "-" + po.ReferenceNumber).Contains(searchModel.OrKey_Referencenumber_ConsignmentID)
|| (po.VendorProvidedID != null && po.VendorProvidedID.Contains(searchModel.OrKey_Referencenumber_ConsignmentID))))
&& (searchModel.KeyClientName == null || po.Parcel.Name.ToUpper().Contains(searchModel.KeyClientName.ToUpper()))
&& (searchModel.KeyCountries == null || searchModel.KeyCountries.Contains(po.Parcel.City.Country))
&& (searchModel.KeyOrderStates == null || searchModel.KeyOrderStates.Contains(po.State.Value))
&& (searchModel.KeyFromDateRegisteredToOTS == null || po.DateRegisteredToOTS > searchModel.KeyFromDateRegisteredToOTS)
&& (searchModel.KeyToDateRegisteredToOTS == null || po.DateRegisteredToOTS < searchModel.KeyToDateRegisteredToOTS)
&& (searchModel.KeyFromDateDeliveredToVendor == null || po.DateRegisteredToVendor > searchModel.KeyFromDateDeliveredToVendor)
&& (searchModel.KeyToDateDeliveredToVendor == null || po.DateRegisteredToVendor < searchModel.KeyToDateDeliveredToVendor);
return expression;
}
public Func<ParcelOrder, bool> UserPrivilegeValdationExpression(string userId)
{
var roles = GetRolesForUser(userId);
Func<ParcelOrder, bool> expression =
po => po.ID == 1;
if (roles != null)
{
if (roles.Contains("ParcelAdministrator"))
expression =
po => true;
else if (roles.Contains("RegionalAdministrator"))
{
var user = db.AspNetUsers.First(u => u.Id == userId);
if (user.RegionalAdministrator != null)
{
expression =
po => po.HubID == user.RegionalAdministrator.HubID;
}
}
else if (roles.Contains("Customer"))
{
var customerID = db.AspNetUsers.First(u => u.Id == userId).CustomerID;
expression =
po => po.CustomerID == customerID;
}
else
{
expression =
po => false;
}
}
return expression;
}
If you can possibly avoid it, don't count for pagination. Just return the first page. It's always expensive to count and adds little to the user experience.
And in any case you're building the dynamic search wrong.
You're calling IEnumerable.Count(Func<ParcelOrder,bool>), which will force client-side evaluation where you should be calling IQueryable.Count(Expression<Func<ParcelOrder,bool>>). Here:
Func<ParcelOrder, bool> completeExpression = order => userPrivilegeValidation(order) && criteriaMatchValidation(order);
searchModel.PaginationTotalCount = db.ParcelOrder.Count(completeExpression);
But there's a simpler, better pattern for this in EF: just conditionally add criteria to your IQueryable.
eg put a method on your DbContext like this:
public IQueryable<ParcelOrder> SearchParcels(ParcelOrderSearchModel searchModel)
{
var q = this.ParcelOrders();
if (searchModel.KeyUploadID != null)
{
q = q.Where( po => po.UploadID == searchModel.KeyUploadID );
}
if (searchModel.KeyCustomerID != null)
{
q = q.Where( po.CustomerID == searchModel.KeyCustomerID );
}
//. . .
return q;
}

Store math operator in variable

I am creating an application in C# MVVM. I have a simple question. Is there any possibility to store math operator in variable? I have a code like that:
public ICollectionView FilteredCollection
{
get
{
return filteredCollection;
}
set
{
filteredCollection = value;
OnPropertyChanged("FilteredCollection");
}
}
FilteredCollection.Filter = x => (
(string.IsNullOrEmpty(DynamicSearchEmployeeName) || ((Employee)x).EmployeeName.Contains(DynamicSearchEmployeeName))
&& (DynamicSearchEmployeeID == null || ((Employee)x).EmployeeID == DynamicSearchEmployeeID)
&& (string.IsNullOrEmpty(DynamicSearchEmployeeSalary) || ((Employee)x).EmployeeSalary == Convert.ToInt32(DynamicSearchEmployeeSalary))
&& (string.IsNullOrEmpty(DynamicSearchEmployeeDesigner) || ((Employee)x).EmployeeName.Contains(DynamicSearchEmployeeDesigner))
&& (string.IsNullOrEmpty(DynamicSearchEmployeeEmailID) || ((Employee)x).EmployeeName.Contains(DynamicSearchEmployeeEmailID))
);
What I want to achieve:
In fourth line (DynamicSearchEmployeeSalary) math operator should be depended on following conditions:
if (IsPressedEqual == true)
VARIABLE = "=="
if (IsPressedLess == true)
VARIABLE = "<"
if (IsPressedGreater == true)
VARIABLE = ">"
if (IsPressedLess == true && IsPressedEqual == true)
VARIABLE = "<="
if (IsPressedGreater == true && IsPressedEqual == true)
VARIABLE = ">="
Scenario:
For example I put a value like 10000 in textbox, then click on button with "=" operator. As a result I want to receive Employees with Salary equals than 10000.
Then I click on ">". And I have Employees with Salary greater and equals 10000.
FilteredCollection.Filter = x => (
(string.IsNullOrEmpty(DynamicSearchEmployeeName) || ((Employee)x).EmployeeName.Contains(DynamicSearchEmployeeName))
&& (DynamicSearchEmployeeID == null || ((Employee)x).EmployeeID == DynamicSearchEmployeeID)
&& (string.IsNullOrEmpty(DynamicSearchEmployeeSalary) || ((Employee)x).EmployeeSalary VARIABLE Convert.ToInt32(DynamicSearchEmployeeSalary))
&& (string.IsNullOrEmpty(DynamicSearchEmployeeDesigner) || ((Employee)x).EmployeeName.Contains(DynamicSearchEmployeeDesigner))
&& (string.IsNullOrEmpty(DynamicSearchEmployeeEmailID) || ((Employee)x).EmployeeName.Contains(DynamicSearchEmployeeEmailID))
I've made a simple Rule Based Engine ... I think it will help you in your issue ...
please find it as a nuget package here: https://www.nuget.org/packages/IbnSherien.RuleBasedEngine/
you can create a rule like this:
var rule = RuleEngine.CreateRule<Employee>()
.If<Employee>(e => e.EmployeeSalary).GreaterThan(DynamicSearchEmployeeSalary)
.Validate();
FilteredCollection.Filter = x => (
(string.IsNullOrEmpty(DynamicSearchEmployeeName) || ((Employee)x).EmployeeName.Contains(DynamicSearchEmployeeName))
&& (DynamicSearchEmployeeID == null || ((Employee)x).EmployeeID == DynamicSearchEmployeeID)
&& (string.IsNullOrEmpty(DynamicSearchEmployeeSalary) || rule.Match((Employee)x).IsMatch)
&& (string.IsNullOrEmpty(DynamicSearchEmployeeDesigner) || ((Employee)x).EmployeeName.Contains(DynamicSearchEmployeeDesigner))
&& (string.IsNullOrEmpty(DynamicSearchEmployeeEmailID) || ((Employee)x).EmployeeName.Contains(DynamicSearchEmployeeEmailID))
feel free to add any comments or contribute to the package

Using Checkbox to join indexes for search in c# for mysql

I have made a simple database search program using c# linq and mysql(code below) which works pretty well. This database has 16 columns 6 of which are for address (State,City,District,Street, Building Name, Door Number). My code now searches for many variations of indexes aside from anything related to address and as seen below ID is overriding value. What my prof. wants is to search with ID and address values to find who might be from the same place. The way this is wanted is to have a checkbox.
If checkbox is clicked and ID entered the search result returned with everyone with the same address and if nobody else has the same address then just the entered ID value to return.The rest of the index values doesn't needed for this operation. My problem with this whole equation is I can't find any applicable way to join the 6 address columns and do a double search with ID and the whole adress. I have to use linq as it is required.
Code Sample;
var query = from i in sqlcmd.table select i;
if (ID.Text.Length > 0)
{
double id = Convert.ToDouble(ID.Text);
query = query.Where(s => s.ID == id);
}
else
{
if (Name.Text.Length > 0)
{
query = query.Where(s => s.Name == Name.Text);
}
if (Sname.Text.Length > 0)
{
query = query.Where(s => s.Sname == Sname.Text);
}
if (ClassList.Text.Length > 0)
{
query = query.Where(s => s.ClassList == ClassList.Text);
}
}
gridview.DataSource = query.ToList();
P.S: Thx to #juancarlosoropeza for heads-up of the mess of a question I made.
just include the check value on the if conditions.
if (chkName.Checked && Name.Text.Length > 0)
{
query = query.Where(s => s.Name == Name.Text);
}
if (chkSName.Checked && Sname.Text.Length > 0)
{
query = query.Where(s => s.Sname == Sname.Text);
}
if (chkClassList.Checked && ClassList.Text.Length > 0)
{
query = query.Where(s => s.ClassList == ClassList.Text);
}
I don't know if I completely understood what you are looking for but I'll give it a try.
If I got you right you are looking for a way to find anybody who has the same address as the person with a given ID. If you want to exclude the person with the given ID just uncomment the last line in the where-clause of the query.
var query = from i in sqlcmd.Table select i;
if (ID.Text.Length > 0)
{
var personGivenByID = from person in query.AsEnumerable()
where person.ID == Convert.ToDouble(ID.Text)
select person;
var sameAddressLikeGivenPerson = from row in query.AsEnumerable()
where row.State == personGivenByID.FirstOrDefault().State
&& row.City == personGivenByID.FirstOrDefault().City
&& row.District == personGivenByID.FirstOrDefault().District
&& row.Street == personGivenByID.FirstOrDefault().Street
&& row.BuildingName == personGivenByID.FirstOrDefault().BuildingName
&& row.DoorNumber == personGivenByID.FirstOrDefault().DoorNumber
//&& row.ID != personGivenByID.FirstOrDefault().ID
select row;
gridview.DataSource = sameAddressLikeGivenPerson != null ? sameAddressLikeGivenPerson : sameAddressLikeGivenPerson;
}

How to apply Contains( ) on a string array using LINQ to SQL c#

Good Day!
string[] keywords = toolStripTextBoxSearch.Text.Split(' ');
IQueryable<employee> query = db.employees;
foreach (string keyword in keywords)
{
query = query.Where(data => data.empName.Contains(keyword)
|| data.bank.bankCode.Contains(keyword)
|| data.bank.bankName.Contains(keyword)
|| data.department.deptName.Contains(keyword)
|| data.department.deptCode.ToString().Contains(keyword)
|| data.designation.desigText.Contains(keyword)
|| data.empBankAccount.Contains(keyword)
|| data.empBasicSalary.Value.ToString().Contains(keyword)
|| data.empIncomeTax.ToString().Contains(keyword)
|| data.empName.Contains(keyword)
|| data.empNTN.Contains(keyword)
|| data.empTicketNumber.Contains(keyword)
|| data.grade.gradeText.Contains(keyword));
}
dataGridViewEmployee.DataSource = query;
Now if I write "a b" in the textbox, it shows no result while on writing "a" only or "b" only the gridview is showing multiple results.
The reason why writing "a b" does not show any result is because the generatedSQL Query is probably not like how you wanted it to be.
When there's only one keyword, such as "a" or "b" only, the SQL query would be like:
SELECT empName, bankCode, bankName, ...
FROM Employees
WHERE (empName LIKE '%a%') OR (bankCode LIKE '%a%') OR (bankName LIKE '%a%') ...
But when there's more than one keywords, such as "a b", then the generated SQL query would be like:
SELECT empName, bankCode, bankName, ...
FROM Employees
WHERE ((empName LIKE '%a%') OR (bankCode LIKE '%a%') OR (bankName LIKE '%a%') ...)
AND ((empName LIKE '%b%') OR (bankCode LIKE '%b%') OR (bankName LIKE '%b%') ...) ...
Notice the AND operator there, what you wanted here is probably an ALL OR condition...
One way to easily achieve what you wanted is by using a PredicateBuilder.
Your updated example using PredicateBuilder would be something like this:
string[] keywords = toolStripTextBoxSearch.Text.Split(' ');
IQueryable<employee> query = db.employees;
Expression<Func<employee, bool>> predicate = PredicateBuilder.False<employee>();
foreach (string keyword in keywords)
{
predicate = predicate.Or(data => data.empName.Contains(keyword) || data.bank.bankCode.Contains(keyword) || data.bank.bankName.Contains(keyword) || data.department.deptName.Contains(keyword) || data.department.deptCode.ToString().Contains(keyword) || data.designation.desigText.Contains(keyword) || data.empBankAccount.Contains(keyword) || data.empBasicSalary.Value.ToString().Contains(keyword) || data.empIncomeTax.ToString().Contains(keyword) || data.empName.Contains(keyword) || data.empNTN.Contains(keyword) || data.empTicketNumber.Contains(keyword) || data.grade.gradeText.Contains(keyword));
}
dataGridViewEmployee.DataSource = query.Where(predicate);
string[] keywords = toolStripTextBoxSearch.Text.Split(' ');
IQueryable<employee> query = db.employees;
query = query.Where(data => keywords.Contains(data.empName) ||
keywords.Contains(data.bank.bankCode) ||
keywords.Contains(data.bank.bankName) ||
keywords.Contains(data.department.deptName) ||
keywords.Contains(data.department.deptCode.ToString()) ||
keywords.Contains(data.designation.desigText) ||
keywords.Contains(data.empBankAccount) ||
keywords.Contains(data.empBasicSalary.Value.ToString()) ||
keywords.Contains(data.empIncomeTax.ToString()) ||
keywords.Contains(data.empName) ||
keywords.Contains(data.empNTN) ||
keywords.Contains(data.empTicketNumber) ||
keywords.Contains(data.grade.gradeText));
On of the way is to use DynamicLinq:
using System.Linq.Dynamic;
// ....
var predicateBuilder = new StringBuilder();
for (var i = 0; i < keywords.Length; i++)
{
predicateBuilder.AppendFormat("empName.Contains(#{0})
OR data.bank.bankCode.Contains(#{0})
OR data.bank.bankName.Contains(#{0})
OR ... and so on", i);
if (i < keywords.Length - 1)
{
predicateBuilder.Append(" OR ");
}
}
query = query.Where(predicateBuilder.ToString(),
keywords.Cast<object>().ToArray());
var result = (IEnumerable<YourClass>)query.ToList();
Cons
Not strongly typed.
You can make mistake in Prop name,
Refactor-not-friendly - you have to remember that prop name has changed and do it manually in string.. for example
So use it, when nobody will gave you better solution. More on this blog.

Categories