Advanced search with LINQ to EF - linq

I have up to 4 values: string firstName, string lastName, string ssn, DateTime dateOfInjury. The user can enter any one of these or any combination. If they enter more than one, I want to return results using AND. For example, where firstName matches (if that's all they enter), or if firstName AND lastName match if they enter both of them, and so on. What's the best way to do this with LINQ? I'm hoping there's something more elegant that a giant switch statement.
I was planning on building the where clause dynamically, but it doesn't seem like that will work: Building dynamic where clauses in LINQ to EF queries.

Just build up your query. If you have a sequence of Where calls, those are AND'd together.
IQueryable<Customer> query = source.Customers;
if (firstName != null)
{
query = query.Where(c => c.FirstName == firstName);
}
if (lastName != null)
{
query = query.Where(c => c.LastName == lastName);
}

Related

LINQ - Buidling a search query

I am building up a search query for my customer search function:
I have all these fields passing into the function and wonder what is the best way to build up the LINQ expression. Some of the fields maybe an empty string and the search should be using "contains" instead of searching the exact field string
public List<Customer> SearchCustomer(
string membershipID,
string preferName,
string firstName,
string lastName,
string nric,
string phoneNumber,
string email,
DateTime dob,
string gender,
string address,
Boolean vip,
bool isDeleted)
You can manage multiple filter parameters in the following way:
var result = customerCollection.
.Where(c => membershipID != null ? c.membershipId.Contains(membershipID) : true)
.Where(c => preferName != null ? c.preferName.Contains(membershipID) : true)
...
.ToList();
I hope you get the idea

EF6/Code First and indexes: Is there anything special to do to access/use indexes?

I'm in my first Code First project. I just learned how to add an index on two columns.
[Required]
[Index("IX_NameAndCity", 1, IsUnique = false)]
[MaxLength(900)]
public string Name { get; set; }
[Index("IX_NameAndCity", 2, IsUnique = false)]
[MaxLength(900)]
public string City { get; set; }
Does this look right? ^^^
Is there anything special in the LINQ to utilize these indexes or is it transparent? I was half expecting to see a choice in my LINQ for '.IX_NameAndCity'.
Here's what I'm doing now:
var property = _propertyRepository
.GetProperties()
.FirstOrDefault(x => x.Name == name && x.City == city);
Should it be something like:
var property = _propertyRepository
.GetProperties()
.FirstOrDefault(x => x.IX_NameAndCity.name == name && IX_NameAndCity.City == city);
Or does it automagically know there's an index?
Thanks all!
The index is created on the database server. Just like you don't want to explicitly refer to the index when you write a SQL query, you don't want to explicitly refer to the index when you write a LINQ query. And actually your entity won't have an IX_NameAndCity property. So simply use your first query:
var property = _propertyRepository
.GetProperties()
.FirstOrDefault(x => x.Name == name && x.City == city);
Entity Framework will construct the corresponding SQL query and pass it to the database server, and the database server will know it should (or possibly should not) use the index to speed up the query execution. It's transparent; don't worry about it.

Build string for Linq WHERE clause depending on multiple checkbox choices

I can build the WHERE clause with a varying number of "AND"s in a string in PHP and then concatenate it to the end of my SELECT statement before running. I am trying to figure out how to do this in MVC Controller ActionResult event using LINQ
Usually something like
var strSQL ="SELECT field1, field3, field5 FROM tblWhatever WHERE 1-1"
(the 1=1 allows flexibilty in how many AND's I build, not having to worry about the first one)
then I build the string of ANDs or just one and concatenate
strSQL .= " AND DWPCEU != null "
strSQL .=" AND DEQCEU !=null "
then I run the SQL (in PHP)
Got any idea how I would build a string of ANDs in a Controller ActionResult?
this limited example below works, but only for one AND. I know I can add "&&"s ad nauseum
but would rather build it elsewhere since there are 4x4 number of checkbox choices.
There are 4 checkboxes and none, any, or all can be checked.
var courses = from m in _db.Courses select m;
if (!String.IsNullOrEmpty(searchString))
{
if (bolDWP == true)
{
courses = courses.Where(s => s.CourseTitle.Contains(searchString) **&& s.CEUDWP !=null**);
}
else
{
courses = courses.Where(s => s.CourseTitle.Contains(searchString));
}
}
I'm guessing you want to do something like this:
var courses = _db.Courses.AsQueryable();
if (!String.IsNullOrEmpty(searchString))
{
courses = courses.Where(s => s.CourseTitle.Contains(searchString));
}
if (bolDEQ)
{
courses = courses.Where(s => s.CEUDEQ != null);
}
if (bolDWP)
{
courses = courses.Where(s => s.CEUDWP != null);
}

How do I buid a WCF Query on the fly?

I'd like to build some linq or alternatively, build a query string on the fly and pass it to a WCF Data Service (with Entity Framework data model).
Something like this:
public List<DocumentInformationRecord> SearchClientDocs(string clientCode,
string clientName, string contactName, string groupCode, string groupName,
string filename, string createdby, DateTime dateFrom, DateTime dateTo)
{
List<DocumentInformationRecord> results = new List<DocumentInformationRecord>();
if(!string.IsNullOrEmpty(clientCode))
//Add the client code clause...
etc..
var qry = from c in context.DocumentInformationRecord.where(dynamicQuery);
//Etc......
Any ideas? I tried the predicate builder (http://www.albahari.com/nutshell/predicatebuilder.aspx) but got some invalid operation exceptions.....
I am not sure I entirely understand your question, but I have sometimes written code to build up LINQ queries with different parts depending on input. Typically that goes something like this:
var qry = from item in someList
select item;
if (nameFilter != null)
{
qry = qry.Where(item => item.Name == nameFilter);
}
if (someOtherFilter != null)
{
qry = qry.Where(item => item.SomeOtherStuff == someOtherFilter);
}
// and so on
That way you can build the query step by step. You can do this because of deferred execution; the query will not be executed against the data source until you start iterating over the result.
Not sure if it will suit your situation, but you can use expression trees to build dynamic queries. There is a good tutorial here

Linq nested select new not working

I'm trying to get eager loading working with Subsonic, and it's been returning null for me.
In the method below, I'm trying to hydrate a domain model (UserModel) which contains another domain model (CompanyModel). However, with the code below, UserModel.Company is always null.
What am I missing here. Any help would be appreciated.
public IList<UserModel> GetUsers()
{
return (from u in SubsonicSqlServer.Users.All()
select new UserModel
{
UserId= u.UserId,
Company = (from c in u.Companies
select new CompanyModel
{
CompanyId = c.CompanyId,
CompanyName = c.CompanyName
}).SingleOrDefault(),
FirstName = u.FirstName,
LastName = u.LastName,
BirthDate = u.BirthDate
}).ToList();
}
Update (08/11/09):
More toying around with the code, I found out that setting CompanyId in the following example doesn't work either. I initially thought this was an issue with Subsonic, but if the code below doesn't work, I'm guessing it has something to do with my Linq statement. Any ideas?
public IList<UserModel> GetUsers()
{
return (from u in SubsonicSqlServer.Users.All()
select new UserModel
{
UserId= u.UserId,
CompanyId = Guid.NewGuid(),
FirstName = u.FirstName,
LastName = u.LastName,
BirthDate = u.BirthDate
}).ToList();
}
Update (11/17/2009):
Still haven't found a solution. But we are switching to nHibernate (not because of this issue).
"UserModel.Company is always null."
since you are setting this with an expression that ends with .SingleOrDefault(), I'm going to suggest that the query isn't returning a single item. Start investigating there. If you are expecting exactly one item in u.Companies, change to .Single() and force an early failure.
You can do the .Single() before creating the new CompanyModel object, I think.
As for style, I like the query comprehension syntax ("from x in y select") but find it awkward when combined with traditional dot-notation syntax. It's just hard to read. (LINQ - Fluent and Query Expression - Is there any benefit(s) of one over other?).
Consider using let in the query comprehension to make it clearer.
Also, since a query already returns an IEnumerable<T>, and calling ToList() forces all items to be realized, I would modify my method to return IEnumerable<T> if possible.
So, in your case, I would refactor the first to say:
public IEnumerable<User> GetUsers()
{
return from u in SubsonicSqlServer.Users.All()
let c = u.Companies.Single()
select new UserModel
{
UserId = u.UserId,
Company = new CompanyModel
{
CompanyId = c.CompanyId,
CompanyName = c.CompanyName
},
FirstName = e.FirstName,
LastName = e.LastName,
BirthDate = e.BirthDate
};
}
If it makes sense in your object model, you could modify User to have a constructor that takes whatever type u is, and it gets even simpler:
return from u in SubsonicSqlServer.Users.All()
select new UserModel (u);
or even
return SubsonicSqlServer.Users.All().Select(u => new UserModel (u));
Two things
You're returning a List<UserModel> when your method's signature line says IList<User> does UserModel inherit from User?
Am I missing something, where does e come from?
FirstName = e.FirstName,
LastName = e.LastName,
BirthDate = e.BirthDate Blockquote
Please check out my fork # github (http://github.com/funky81/SubSonic-3.0/commit/aa7a9c1b564b2667db7fbd41e09ab72f5d58dcdb) for this solution, actually there's a problem when subsonic try to project new type class, so there's nothin wrong with your code actually :D

Resources