FindAsync not finding results with DateTime comparison - c#

using MongoDB.Bson;
public async Task<List<Person>> Get(string lastName, string firstName, string dob, string id)
{
var dobParse = DateTime.Parse(dob);
var persons = await _patients.FindAsync<Patient>(person =>
(String.IsNullOrWhiteSpace(lastName) || person.lastName == lastName) &&
(String.IsNullOrWhiteSpace(firstName) || person.firstName == firstName) &&
(String.IsNullOrWhiteSpace(dob) || person.dob.Equals(DateTime.Parse(dob))) &&
(String.IsNullOrWhiteSpace(id) || person.Id == id));
return await persons.ToListAsync();
}
When isolated it looks like all other comparisons work as they return results, except for this condtion (String.IsNullOrWhiteSpace(dob) || person.dob.Equals(DateTime.Parse(dob))). I've tried various ways of checking for a null dob DateTime including passing it in as a nullable DateTime and checking if it has value, as well as various ways of comparing the 2 DateTime objects.
Here is a sample record and parameters used to query it:
{
"_id": {
"$oid": "610f727c7ec433f528bf3727"
},
"firstName": "John",
"lastName": "Doe",
"dob": "1980-01-30T00:00:00"
}
QueryParams: lastName=Doe&firstName=John&dob=1980-01-30T00:00:00&id=610f727c7ec433f528bf3727
The DateTimes are identical.
I've added some debug code to compare the DateTimes and added setting the search DateTime kind to UTC and adding the UTC attribute to the model property for "Person".
public async Task<List<Person>> Get(string lastName, string firstName, string dob, string id)
{
var dobParse = DateTime.Parse(dob,CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal);
var Persons = await _Persons.FindAsync<Person>(person =>
(String.IsNullOrWhiteSpace(lastName) || person.lastName == lastName) &&
(String.IsNullOrWhiteSpace(firstName) || person.firstName == firstName) &&
//person.dob == dobParse &&
(String.IsNullOrWhiteSpace(id) || person.Id == id));
var resultDob = Persons.FirstOrDefault().dob;
if (dobParse == resultDob)
{
var match = true;
}
return await Persons.ToListAsync();
}
In the example above match is set as true as if (dobParse == resultDob) resolves as true. However, no results from the DB are still returned despite the other conditions being true (firstName, lastName, and id).

Related

How to sort List using custom column values in linq?

Net core, Ef core and linq. I have table with column status. It holds the values New, In-Progress and closed. When I will query all the rows with New should come first followed by in-progress and closed. Below is my code.
var Requests = await this.RequestRepository.GetAsync(x => x.IsActive == true && x.CreatedBy == LoggedInUser, null, x => x.Country).ConfigureAwait(false);
Below is my GetAsync method
public async Task<IEnumerable<T>> GetAsync(Expression<Func<T, bool>> filter = null, Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null, params Expression<Func<T, object>>[] includes)
{
IQueryable<T> query = this.dbSet;
foreach (Expression<Func<T, object>> include in includes)
{
query = query.Include(include);
}
if (filter != null)
{
query = query.Where(filter);
}
if (orderBy != null)
{
query = orderBy(query);
}
return await query.ToListAsync().ConfigureAwait(false);
}
So I am expecting all the rows with status New should come first then In-Progress and closed. I am not finding anyway to figure it out. Can someone help me to write this. Any help would be appreciated. Thank you
Your life would probably be a lot easier if you throw this "helper" method away and just use LINQ straight. Look how much more obviously readable it is:
var apps = db.FundingApplications
.Include(x => x.Applicant)
.Where(x => x.ApplicationDate.Year == DateTime.Now.Year)
.OrderBy(x => (int)x.Status)
(I skipped the await/async for brevity, not because I'm advocating sync)
Status of course being an enum like:
enum Status{
New, Inprogress, Closed
}
If your enum is awkwardly NOT in numeric order like this but is instead eg
enum Status {
New = 20,
InProgress = 1,
Closed = 99
}
Then you could order it by descending after you ToString it (you'll notice the names are in reverse alphabet order) or create a mapping using a dictionary that maps eg d[New] = 0, d[InProgress] = 1 ..., or do an (in-line) if set in the OrderBy.
OrderByDescending(x => x.Status.ToString("g"));
var d = new Dictionary<status, int>() {
{New, 0}, {InProg,1}, {Closed,2}
};
OrderBy(x => d[x.Status]);
OrderBy(x => x.Status == Status.New ? 0 : (x.Status == Status.InProg ? 1 : 2))
Only the last of these has any real chance of being executed on the server though, and ordering by its name will only work If you don't rename them or add new names that break the ordering.
I do also appreciate the OrderBy/ThenBy given in the other answer and think it's good but I think care should be given to testing whether it executed on the server or the client because it carries out a boolean compare and a lot of db don't use booleans as a data type or if they do they might sort falsy (0) ahead of truey (1)
OrderBy(x => x.Status == New)
Might just be then that it sorts all closed and InProg ahead of New because the result of the boolean if evaluated by the server is 0 for InProg/closed and 1 for new. MySql and Postgres would be my top picks for worrying that this would be server evaluated because they do allow boolean type values in contexts other dbs don't.
So, be careful that a) this kind of ordering is evaluating where you expect and want (client/server) and b) if it really is evaluating on the server that the server orders it as you want
Edit, just saw your comment that indicates that Status isn't an enum but some set of string constants??
If your DB values are literally string and status was never an enum then you can just order them by descending
OrderByDescending(x => x.Status)
I have made a sample code according to your requirement. It's working fine on mine. Please refer to this. Hope this will work on your code too.
using System;
using System.Collections.Generic;
using System.Linq;
namespace Test
{
public class Program
{
public static void Main(string[] args)
{
List<Name> list = new List<Name>
{
new Name { FirstName = "Nishan1", LastName = "Dhungana1", Status = Status.Closed},
new Name { FirstName = "Nishan2", LastName = "Dhungana2", Status = Status.New},
new Name { FirstName = "Nishan3", LastName = "Dhungana3", Status = Status.New},
new Name { FirstName = "Nishan4", LastName = "Dhungana4", Status = Status.Closed},
new Name { FirstName = "Nishan5", LastName = "Dhungana5", Status = Status.Closed},
new Name { FirstName = "Nishan6", LastName = "Dhungana6", Status = Status.InProgress},
new Name { FirstName = "Nishan7", LastName = "Dhungana7", Status = Status.Closed},
new Name { FirstName = "Nishan8", LastName = "Dhungana8", Status = Status.InProgress},
new Name { FirstName = "Nishan9", LastName = "Dhungana9", Status = Status.InProgress},
new Name { FirstName = "Nishan10", LastName = "Dhungana10", Status = Status.New},
new Name { FirstName = "Nishan11", LastName = "Dhungana11", Status = Status.New}
};
list = list.OrderByDescending(x => x.Status == Status.New)
.ThenByDescending(x => x.Status == Status.InProgress)
.ThenByDescending(x => x.Status == Status.Closed)
.ToList();
Console.WriteLine("hey");
Console.ReadLine();
}
}
public class Name
{
public string FirstName { get; set; }
public string LastName { get; set; }
public Status Status { get; set; }
}
public enum Status
{
New = 1,
InProgress = 2,
Closed = 3
}
}

Linq to Entities orderby parent table value. (MVC)

I have a Member table which has a foreign key from ASPNETUSERS table. My ASPNETUSERS table has additional fields in it for First Name and Last Name which I would like to use as sort values in my Members Controller.
var members = from m in db.Members.Include(m => m.AspNetUser).Include(m => m.Location) select m;
This is currently the initial query i am retrieving to get me all the members and searching is easy as i can use the following syntax.
members = members.Where(m => m.AspNetUser.LastName.Contains(searchString)
|| m.AspNetUser.HomePhone.Contains(searchString)
|| m.AspNetUser.MobilePhone.Contains(searchString)
|| m.AspNetUser.FirstName.Contains(searchString)
|| m.IdentificationNumber.Contains(searchString));
However when i try to do my sorting e.g.
members = members.OrderByDescending(m => m.AspNetUser.LastName);
It "works" however it doesn't actually sort but the Last name of the related table.
Can someone advise me as to what I am doing wrong.
Thank you.
Update: Below is full Action Result Method.
public ActionResult Index(string sortOrder, string searchString, string Command)
{
//Redirect back to login page if not authenticated
if (!HttpContext.User.Identity.IsAuthenticated)
{
return RedirectToAction("Login", "Account");
}
ViewBag.LastNameSortParm = String.IsNullOrEmpty(sortOrder) ? "lastname_desc" : "";
ViewBag.FirstNameSortParm = sortOrder == "firstname" ? "firstname_desc" : "firstname";
var members = from m in db.Members.Include(m => m.AspNetUser).Include(m => m.Location) select m;
if (Command == "Search")
{
if (!String.IsNullOrEmpty(searchString))
{
members = members.Where(m => m.AspNetUser.LastName.Contains(searchString)
|| m.AspNetUser.HomePhone.Contains(searchString)
|| m.AspNetUser.MobilePhone.Contains(searchString)
|| m.AspNetUser.FirstName.Contains(searchString)
|| m.IdentificationNumber.Contains(searchString));
}
}
else if (Command == "Reset")
{
}
switch (sortOrder)
{
case "lastname_desc":
members = members.OrderByDescending(m => m.AspNetUser.LastName);
break;
case "firstname":
members = members.OrderBy(m => m.AspNetUser.FirstName);
break;
case "firstname_desc":
members = members.OrderByDescending(m => m.AspNetUser.FirstName);
break;
default:
members = members.OrderBy(m => m.AspNetUser.LastName);
break;
}
return View(members.ToList());
}

Dynamic Where clause with unknown number of parameters

I have searched for an answer to my question, but have been unable to find one that meets my needs.
The following two code snippets return the same thing and I have no preference which one to use, I am just including both in case it helps someone answer my question
private List<MyClass> GetMyClass(string name, string city, string state, string zip)
{
using (MyEntities ctx = new MyEntities())
{
var results = from a in ctx.MyEntity
where (a.Name == name &&
a.City == city &&
a.State == state &&
a.ZIP == zip)
select a;
return results.ToList();
}
}
private List<MyClass> GetMyClass(string name, string city, string state, string zip)
{
using (MyEntities ctx = new MyEntities())
{
var results = ctx.MyEntity.Where(a => a.Name == name)
.Where(a => a.City == city)
.Where(a => a.State == state)
.Where(a => a.ZIP == zip)
.Select(a => a);
return results.ToList();
}
}
For the purposes of this example, let's say I have a search screen which requires users to enter a Name and a City; State and ZIP are optional. The query must at least search by those two fields, and any additional fields, if necessary.
Obviously, with my above examples, if a user searches only by Name and City, they would not get any results as the queries would be trying to match State == null and ZIP == null since those two parameters where not supplied.
How can I rewrite this code to only search on the fields that parameters have been supplied for?
You could just chain them, something like:
var results = ctx.MyEntity.AsQueryable();
if(name != null)
results = results.Where(a => a.Name == name);
// ... snip ...
if(zip != null)
results = results.Where(a => a.ZIP == zip)
return results.ToList();
var results = from a in ctx.MyEntity
where ((a.Name == name || name == null) &&
(a.City == city || city == null) &&
(a.State == state || state == null) &&
(a.ZIP == zip) || zip == null)
select a;

Linq to SQL multiple conditional where clauses

At the moment I am retrieving my results as follows :
public List<claim> GetClaims()
{
return _db.claims.OrderBy(cl => cl.claimId).ToList();
}
But now I am trying to add up to 8 conditional where clauses based on filters above my listview.
So I turned into:
public List<claim> GetFilteredClaims(string submissionId, string claimId,
string organization, string status,
string filterFromDate, string filterToDate,
string region, string approver)
{
return _db.claims.Where(cl => cl.submissionId == 5).ToList();
}
How can I do a check for each filter to add a where clause only if they contain a value?
There is no reason why you can't just keep filtering the results by calling .Where several times. Because of the deferred execution of LINQ to SQL it will all be executed in one SQL statement:
public List<claim> GetFilteredClaims(string submissionId, string claimId,
string organization, string status,
string filterFromDate, string filterToDate,
string region, string approver)
{
IQueryable<claim> filteredClaims = _db.claims;
if (!string.IsNullOrWhiteSpace(submissionId))
{
filteredClaims = filteredClaims.Where(claim => claim.submissionId == submissionId);
}
if (!string.IsNullOrWhiteSpace(claimId))
{
filteredClaims = filteredClaims.Where(claim => claim.claimId == claimId);
}
...
return filteredClaims.ToList();
}
If you will ever need to add OR conditions, you could take a look at PredicateBuilder.
You could group each filter option with an OR null condition, and chain them all together with AND, like so:
public List<claim> GetFilteredClaims(string submissionId, string claimId, string organization, string status, string filterFromDate, string filterToDate, string region, string approver)
{
return _db.claims
.Where(cl => (cl.submissionId == submissionId || submissionId == null)
&& (cl.claimId == claimId || claimId == null)
&& so on and so on... ).ToList();
}
So if submissionId == null and claimId == "123", it would only filter the results on claimId. You could replace each null with an empty string or whatever your "no value" condition is.
Take a look at LINQKIT http://www.albahari.com/nutshell/linqkit.aspx It will allow you to build predicate
Here is a code that I use but read the documentation above. The predicate will allow you to chain up a bunch of OR or AND or combination of it.
private static IEnumerable<SurveyResult> filterData(string firstName, string lastName, List<SurveyResult> results)
{
var predicate = PredicateBuilder.True<SurveyResult>();
IEnumerable<SurveyResult> a;
if (excludeBadData)
if (firstName != string.Empty)
{
predicate = predicate.And(p => p.User.FirstName.ToLower().Contains(firstName.ToLower()));
}
if (lastName != string.Empty)
{
predicate = predicate.And(p => p.User.LastName.ToLower().Contains(lastName.ToLower()));
}
a = from r in results.AsQueryable().Where(predicate) select r;
return a;
}

c# linq: how to retrieve pieces of data from a returned record

So i have the query:
var query =
from product in db.LUT_ProductInfos
where product.flavor == flavor && product.Container == container
select flavor;
which is returning 1 record (it should always return one record). How do i pull individual attribute values from the result? For example, if it returns 1 record with 3 columns like firstName lastName phoneNumber, and i want to do something with each of the values like
string fName = firstName
string lName = lastName
int pNumber = phoneNumber
without getting into data mapping for objects, what is the most direct way to extract those values from the result variable query
var query =
from product in db.LUT_ProductInfos
where product.flavor == flavor && product.Container == container
select new {product.Foo, product.flavor.Bar, ...};
var row = query.First(); // or Single(), FirstOrDefault(), SingleOrDefault()
string foo = row.Foo;
int bar = row.Bar;
...
This has the advantage that only the desired properties are included in the SELECT statement, and there are no hidden additional round-trips (lazy loading).
var singleResult =
(from product in db.LUT_ProductInfos
where product.flavor == flavor && product.Container == container
select flavor).Single();
string fName = singleResult.firstName
string lName = singleResult.lastName
int pNumber = singleResult.phoneNumber
var row = db.LUT_ProductInfos
.SingleOrDefault(product => product.flavor == flavor && product.Container == container);
if (row != null)
{
string firstName = row.fName;
string lastName = row.lName;
string phone = row.pNumber;
}
The best and easiest way to do this is to recode like this:
var query =
(from product in db.LUT_ProductInfos
where product.flavor == flavor && product.Container == container
select flavor).FirstOrDefault();
it will return the first matched record. If there's no matched record it will retutn null value, otherwise it returns an object of LUT_ProductInfos class. you can also skip records as you wish like this:
var query =
(from product in db.LUT_ProductInfos
where product.flavor == flavor && product.Container == container
select flavor).Skip(25).FirstOrDefault();

Categories

Resources