c# linq where conditional if - c#

I have some linq code that I am trying to refactor because its not very good:
Basically, I am wondering if there is a better way to perform the following:
if (!string.IsNullOrWhiteSpace(_filter.AssignedTo)
{
var query = from ticket in dataClassesDataContext.TicketsIssues
where ticket.ClosedDate == null
&& cUser.GetUserNameUsingGUID(ticket.AssignTicketToUser) == _filter.AssignedTo
select new
{
Priority = ticket.TicketPriority.TicketPriorityName,
Description = ticket.Description.Replace("\n", ", "),
};
}
else
{
var query = from ticket in dataClassesDataContext.TicketsIssues
where ticket.ClosedDate == null
select new
{
Priority = ticket.TicketPriority.TicketPriorityName,
Description = ticket.Description.Replace("\n", ", "),
};
}
They are both identical apart from the where clause is checks for AssignTicketToUser.
I am hoping there is a nicer way to do this to avoid having to use an if else statement? I have a few of these code blocks and dont want to be duplicating code alot!

var query = from ticket in dataClassesDataContext.TicketsIssues
where ticket.ClosedDate == null
&& (string.IsNullOrWhiteSpace(_filter.AssignedTo) ? true : cUser.GetUserNameUsingGUID(ticket.AssignTicketToUser) == _filter.AssignedTo)
select new
{
Priority = ticket.TicketPriority.TicketPriorityName,
Description = ticket.Description.Replace("\n", ", "),
};
You can get rid of the if-else statement altogether. Transfer the if condition it to the 2nd where clause, and remove the !. That second where clause becomes a ternary operator.
If the condition is true, that is if _filter.AssignedTo is null, then don't test _filter.AssignedTo by returning true. If it's not null or empty, then proceed to the clause that was there in your original else block.

one way could be:
var query = from ticket in dataClassesDataContext.TicketsIssues
where ticket.ClosedDate == null
select new
{
Priority = ticket.TicketPriority.TicketPriorityName,
Description = ticket.Description.Replace("\n", ", "),
};
if (!string.IsNullOrWhiteSpace(_filter.AssignedTo)
query = query.Where(w => cUser.GetUserNameUsingGUID(w.AssignTicketToUser) == _filter.AssignedTo));

Take a look at the PredicateBuilder implementation from C# In a Nutshell, the And method should address your issue here, in a more generic way, and help build an understanding of LINQ and expression trees. You would end up with something like:
var query = from ticket in dataClassesDataContext.TicketsIssues
where ticket.ClosedDate == null
select new
{
Priority = ticket.TicketPriority.TicketPriorityName,
Description = ticket.Description.Replace("\n", ", "),
};
if (!string.IsNullOrWhiteSpace(_filter.AssignedTo))
{
query = query.And(ticket => cUser.GetUserNameUsingGUID(ticket.AssignTicketToUser) == _filter.AssignedTo);
}

Related

C# Linq where clause

I'm trying to create a linq query where clause is a constructed variable based on user choices
if (!string.IsNullOrEmpty(txbbox.Text))
{
query = "s.date== DateTime.Parse(txbbox.Text)";
}
if (!string.IsNullOrEmpty(txbbox.Text))
{
query = query + " & (s.type.Contains(txbbox.Text))";
}
there is a way to pass the variable built in the where clause in a LINQ query?
Stemp = (from s in SList
where ***query***
orderby s.DataScadenza
select s).ToList();
Yes; quite simple in this case, actually:
IEnumerable<Whatever> query = SList; // avoid var here, as will impact later assignment
if (!string.IsNullOrEmpty(txbbox.Text))
{
var when = DateTime.Parse(txbbox.Text); // to avoid parsing per item
query = query.Where(s => s.date == when);
}
if (!string.IsNullOrEmpty(txbbox.Text))
{
query = query.Where(s => s.type.Contains(txbbox.Text));
}
Stemp = query.OrderBy(s => s.DateScadenze).ToList();

Dynamic where clause in LINQ?

I am trying to load data based on Dynamic where condition.
string tempQry = string.Empty;
if (!string.IsNullOrEmpty(cusid) && !string.IsNullOrEmpty(mktid))
tempQry = "x=>x.MarketID==" + mktid + "&& x.MasterCustomerID==" + cusid;
if (string.IsNullOrEmpty(cusid))
tempQry = "x=>x.MarketID==" + mktid;
if (string.IsNullOrEmpty(mktid))
tempQry = "x=>x.MasterCustomerID==" + cusid;
_lstOptInInterest = new LinkedList<OptInInterestArea>(
(from a in _lstOptInInterest
join b in _marketoEntities.CustCommPreferences.Where(tempQry)
on new { CODE = a.Code, SUBCODE = a.SubCode } equals new { CODE = b.Option_Short_Name, SUBCODE = b.Option_Short_Subname }
into leftGroup
from b in leftGroup.DefaultIfEmpty()
select new OptInInterestArea()
{
Code = a.Code,
SubCode = a.SubCode,
SubCodeDescription = a.SubCodeDescription,
CodeDescription = a.CodeDescription,
PrevOptIn = b != null && b.OptedIn == true
}).ToList());
It is giving compilation error Where(tempQry).
'System.Data.Entity.DbSet<Market.Data.CustCommPreference>' does not contain a definition for 'Where' and the best extension method overload 'System.Linq.Queryable.Where<TSource>(System.Linq.IQueryable<TSource>, System.Linq.Expressions.Expression<System.Func<TSource,bool>>)' has some invalid arguments
How to handle this?
Where awaits conditions in form of lambdas rather than strings, so you have to refactor your code a little bit (just an idea below):
IQueryable<CustCommPreference> query = _marketoEntities.CustCommPreferences.AsQueryable();
if (!string.IsNullOrEmpty(cusid))
query = query.Where(x => x.MasterCustomerID == cusid);
if (!string.IsNullOrEmpty(mktid))
query = query.Where(x => x.MarketID == mktid);
and later use it:
...
join b in query
...
see this blog by Scott. It should help you sort your issue
The error you are seeing appears to indicate that you are using EF not LINQ to SQL. Please correct your tags if that is the case. If you want to use strings, consider using ObjectQuery's Where method instead of using DBSet. Alternatively, you could build the entire query using EntitySQL.

Using Intersect I'm getting a Local sequence cannot be used in LINQ to SQL implementations of query operators except the Contains operator

I'm using a Linq to SQL query to provide a list of search term matches against a database field. The search terms are an in memory string array. Specifically, I'm using an "intersect" within the Linq query, comparing the search terms with a database field "Description". In the below code, the description field is iss.description. The description field is separated into an array within the Linq query and the intersect is used to compare the search terms and description term to keep all of the comparing and conditions within the Linq query so that the database is not taxed. In my research, trying o overcome the problem, I have found that the use of an in-memory, or "local" sequence is not supported. I have also tried a few suggestions during my research, like using "AsEnumerable" or "AsQueryable" without success.
searchText = searchText.ToUpper();
var searchTerms = searchText.Split(' ');
var issuesList1 = (
from iss in DatabaseConnection.CustomerIssues
let desc = iss.Description.ToUpper().Split(' ')
let count = desc.Intersect(searchTerms).Count()
where desc.Intersect(searchTerms).Count() > 0
join stoi in DatabaseConnection.SolutionToIssues on iss.IssueID equals stoi.IssueID into stoiToiss
from stTois in stoiToiss.DefaultIfEmpty()
join solJoin in DatabaseConnection.Solutions on stTois.SolutionID equals solJoin.SolutionID into solutionJoin
from solution in solutionJoin.DefaultIfEmpty()
select new IssuesAndSolutions
{
IssueID = iss.IssueID,
IssueDesc = iss.Description,
SearchHits = count,
SolutionDesc = (solution.Description == null)? "No Solutions":solution.Description,
SolutionID = (solution.SolutionID == null) ? 0 : solution.SolutionID,
SolutionToIssueID = (stTois.SolutionToIssueID == null) ? 0 : stTois.SolutionToIssueID,
Successful = (stTois.Successful == null)? false : stTois.Successful
}).ToList();
...
The only way I have been successful is to create two queries and calling a method as shown below, but this requires the Linq Query to return all of the matching results (with the number of hits for search terms in the description) including the non-matched records and provide an in-memory List<> and then use another Linq Query to filter out the non-matched records.
public static int CountHits(string[] searchTerms, string Description)
{
int hits = 0;
foreach (string item in searchTerms)
{
if (Description.ToUpper().Contains(item.Trim().ToUpper())) hits++;
}
return hits;
}
public static List<IssuesAndSolutions> SearchIssuesAndSolutions(string searchText)
{
using (BYCNCDatabaseDataContext DatabaseConnection = new BYCNCDatabaseDataContext())
{
searchText = searchText.ToUpper();
var searchTerms = searchText.Split(' ');
var issuesList1 = (
from iss in DatabaseConnection.CustomerIssues
join stoi in DatabaseConnection.SolutionToIssues on iss.IssueID equals stoi.IssueID into stoiToiss
from stTois in stoiToiss.DefaultIfEmpty()
join solJoin in DatabaseConnection.Solutions on stTois.SolutionID equals solJoin.SolutionID into solutionJoin
from solution in solutionJoin.DefaultIfEmpty()
select new IssuesAndSolutions
{
IssueID = iss.IssueID,
IssueDesc = iss.Description,
SearchHits = CountHits(searchTerms, iss.Description),
SolutionDesc = (solution.Description == null)? "No Solutions":solution.Description,
SolutionID = (solution.SolutionID == null) ? 0 : solution.SolutionID,
SolutionToIssueID = (stTois.SolutionToIssueID == null) ? 0 : stTois.SolutionToIssueID,
Successful = (stTois.Successful == null)? false : stTois.Successful
}).ToList();
var issuesList = (
from iss in issuesList1
where iss.SearchHits > 0
select iss).ToList();
...
I would be comfortable with two Linq Queries, but with the first Linq Query only returning the matched records and then maybe using a second, maybe lambda expression to order them, but my trials have not been successful.
Any help would be most appreciated.
Ok, so after more searching more techniques, and trying user1010609's technique, I managed to get it working after an almost complete rewrite. The following code first provides a flat record query with all of the information I am searching, then a new list is formed with the filtered information compared against the search terms (counting the hits of each search term for ordering by relevance). I was careful not to return a list of the flat file so there would be some efficiency in the final database retrieval (during the formation of the filtered List<>). I am positive this is not even close to being an efficient method, but it works. I am eager to see more and unique techniques to solving this type of problem. Thanks!
searchText = searchText.ToUpper();
List<string> searchTerms = searchText.Split(' ').ToList();
var allIssues =
from iss in DatabaseConnection.CustomerIssues
join stoi in DatabaseConnection.SolutionToIssues on iss.IssueID equals stoi.IssueID into stoiToiss
from stTois in stoiToiss.DefaultIfEmpty()
join solJoin in DatabaseConnection.Solutions on stTois.SolutionID equals solJoin.SolutionID into solutionJoin
from solution in solutionJoin.DefaultIfEmpty()
select new IssuesAndSolutions
{
IssueID = iss.IssueID,
IssueDesc = iss.Description,
SolutionDesc = (solution.Description == null) ? "No Solutions" : solution.Description,
SolutionID = (solution.SolutionID == null) ? 0 : solution.SolutionID,
SolutionToIssueID = (stTois.SolutionToIssueID == null) ? 0 : stTois.SolutionToIssueID,
Successful = (stTois.Successful == null) ? false : stTois.Successful
};
List<IssuesAndSolutions> filteredIssues = new List<IssuesAndSolutions>();
foreach (var issue in allIssues)
{
int hits = 0;
foreach (var term in searchTerms)
{
if (issue.IssueDesc.ToUpper().Contains(term.Trim())) hits++;
}
if (hits > 0)
{
IssuesAndSolutions matchedIssue = new IssuesAndSolutions();
matchedIssue.IssueID = issue.IssueID;
matchedIssue.IssueDesc = issue.IssueDesc;
matchedIssue.SearchHits = hits;
matchedIssue.CustomerID = issue.CustomerID;
matchedIssue.AssemblyID = issue.AssemblyID;
matchedIssue.DateOfIssue = issue.DateOfIssue;
matchedIssue.DateOfResolution = issue.DateOfResolution;
matchedIssue.CostOFIssue = issue.CostOFIssue;
matchedIssue.ProductID = issue.ProductID;
filteredIssues.Add(matchedIssue);
}
}

linq - include where parameters

I have a strange question about Linq.
I have this query:
var results = (from p in hotsheetDB.Properties
where p.PCode == pCode
&& p.PropertyStatusID == propertyStatuses
orderby p.PropertyID descending
select new
{
PropertyId = p.PropertyID,
PCode = p.PCode,
PropertyTypeName = p.cfgPropertyType.Name,
FullAddress = p.Address1 + " " + p.Address2,
ZipCode = p.ZipCode.Code,
CityName = p.cfgCity.Name,
LivingSquareFeet = p.LivingSquareFeet,
LotSquareFeet = p.LotSquareFeet,
NumBedrooms = p.NumBedrooms,
NumBathrooms = p.NumBathrooms,
PropertyStatusName = p.cfgPropertyStatuse.Name
});
You notice pCode and propertyStatuses parameters. They are input values from the users. He wants to search by pCode or/and by propertyStatuses.
So, when the user fills in only pCode he wants to return all the records with that pCode having ANY propertyStatuses...well, because propertyStatuses IS in the query but it's null, the query will not return anything (because there is no record with empty(null) propertyStatuses...
Therefore, the question: is there any way to include these where params only whey they have values? (without making separate N queries with all the combination? (I have multiple inputs)
Thanks in advance..
You could change your where clause to make the parts which include null always return true.
For example:
where (pCode == null || p.PCode == pCode)
&& (propertyStatuses == null || p.PropertyStatusID == propertyStatuses)
I'm only guessing here but try:
where p.PCode == pCode &&
(p.PropertyStatusID == null || p.PropertyStatusID == propertyStatuses)

"Only one expression can be specified in the select list when the subquery is not introduced with EXISTS."

I have a fairly complex Linq query:
var q = from eiods in LinqUtils.GetTable<EIOfficialDesignee>()
let eiodent = eiods.Entity
join tel in LinqUtils.GetTable<EntityTelephone>()
on new { EntityID = eiodent.ID, TelephoneType = EntityTelephone.TTelephone.Office } equals new { tel.EntityID, tel.TelephoneType }
into Tel
let Tel1 = Tel.FirstOrDefault()
join fax in LinqUtils.GetTable<EntityTelephone>()
on new { EntityID = eiodent.ID, TelephoneType = EntityTelephone.TTelephone.Fax } equals new { fax.EntityID, fax.TelephoneType }
into Fax
let Fax1 = Fax.FirstOrDefault()
join cell in LinqUtils.GetTable<EntityTelephone>().DefaultIfEmpty()
on new { EntityID = eiodent.ID, TelephoneType = EntityTelephone.TTelephone.Mobile } equals new { cell.EntityID, cell.TelephoneType }
into Mobile
let Mobile1 = Mobile.FirstOrDefault()
where eiods.ID == CurrentEIPatient.EIOfficialDesigneeID
select new {
ID = eiods.ID,
EIODName = eiodent.FormattedName,
Phone = Tel1 != null ? Tel1.FormattedNumber : "",
Fax = Fax1 != null ? Fax1.FormattedNumber : "",
Cellphone = Mobile1 != null ? Mobile1.FormattedNumber : "",
};
This query is returning me an SQL error:
Only one expression can be specified in the select list when the subquery is not introduced with EXISTS
Only one expression can be specified in the select list when the subquery is not introduced with EXISTS
Only one expression can be specified in the select list when the subquery is not introduced with EXISTS
Yes, in triplicate. That's an obvious indicator that the problem with the query is being repeated 3 times i.e. in the 3 different types of phone number.
According to the SQL server documentation, this comes from a malformed query. But this is Linq, for heaven's sake! How can it be malforming the query?
Aside from the main answer, I'd also appreciate any comments you may have about optimizing my query...
Thanks!
Solved it myself, and here it is for anyone else's benefit.
The devil is in the select clause at the end, specifically:
Phone = Tel1 != null ? Tel1.FormattedNumber : "",
Fax = Fax1 != null ? Fax1.FormattedNumber : "",
Cellphone = Mobile1 != null ? Mobile1.FormattedNumber : "",
That FormattedNumber property is a calculated field based on the Number and Extension properties of the EntityTelephone object. When I replace FormattedNumber with Number, everything works fine.
The best solution to this problem is found here.

Categories

Resources