I have a couple of C# business class as follows:
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public string DepartmentCode { get; set; }
public string HireDate { get; set; }
public DateTime DateOfBirth { get; set; }
public DateTime Gender { get; set; }
}
public class EmployeeManagement
{
public List<Employee> GetEmployees(FilterExpression criteria)
{
throw new System.NotImplementedException();
}
}
The goal is to get the list of employees by passing various filter conditions e.g. all employees belonging to particular department, or hired after a particular date or all female employees or a combination of criterias (involving AND or OR conditions). I don't wish to implement many of the overloaded methods for each of the filter criteria since the end users are defining the filter criteria and i can not assume all possible cases.
Can you please help in designing the "FilterExpression" class that i can pass to GetEmployees method? Any other alternate approach suggestion would be welcome.
Thanks.
More details: The employee data is stored in a DB table. I don't want to bring in all the employees in List<Employee> and then filter the data. My goal is to generate the SQL "where clause" from the filter expression so that from the database itself, I get the filtered Employee dataset. I am struggling with the class design of the FilterExpression class as asked above.
You must tell us what kind of expression/filter you want to pass to the method. Otherwise I'll give a cheat answer:
public List<Employee> GetEmployees(Expression<Func<Employee,bool>> predicate)
{
return AllEmployees.Where(predicate.Compile()).ToList();
}
you can use:
var bob = GetEmployees(emp=>emp.Name.Equals("Bob")).FirstOrDefault;
var ITStaff = GetEmployees(emp=>emp.DepartmentCode.Equals("IT"));
Why not use an Expression<Func<Employee,bool>> instead? Although it's typically associated with LINQ it doesn't have to be. You could pass a lambda and examine the expression tree at runtime that way.
var employees = GetEmployees(x => x.HireDate > DateTime.Today.AddDays(-7))
Related
Using EntityFramework context i need to search with many fields.
The EntityDBContext includes
public class Brand
{
public int BrandID { get; set; }
public string BrandName { get; set; }
public string BrandDesc { get; set; }
public string BrandUrl { get; set; }
public virtual ICollection<Product> Products { get; set; }
}
public class Product
{
public string Name {get;set;}
public DateTime CreatedDate {get;set;}
public DateTime ExpiryDate {get;set;}
//The product class also contains many fields.(not shown here)
}
var context = new EntityDBContext();
I would like to search the brand with using the field in Product.
The fields of the product are only known at run time.
How can i build the expression to search the brand using the product fields.
Please see the screenshot.
Thanks,
Binod
First off, I'm a bit unclear on this part of your question:
the fields of the product are only known at run time.
How so? Can you elaborate on this, because I don't see a working implementation of this using EF. What is your database table (Products presumably) set up for? What properties are in that class?
We need to know that before we can give you an accurate answer. However, I'll give you a more general example, maybe that helps you in understanding.
var all_brands_that_sell_shoes = /* But not always ONLY shoes */
myDataContext.Brands
.Where(brand =>
brand.Products.Any(product =>
product.Type == "Shoe")
)
.ToList();
Edit
If I re-read your question, you don't mean that the Product class' properties are not know until runtime; but that you don't know in advance which filters need to be applied and which need to be skipped?
This second answer assumes that is what you want. Again, I don't know your class' properties since you didn't post them, so I'm inventing my own fields for the sake of example.
First, make an object like below. This will be used to aggregate all filters you wish to apply to the selection:
public class MySearchCriteria
{
public string ProductName_Contains { get; set; }
public int ProductWeight_LessThan { get; set; }
public int ProductType_Id { get; set; }
}
When you want to filter the list, you pass a MySearchCriteria object to the method:
public List<Brand> GetFilteredList(MySearchCriteria filters)
{
var brands = myDataContext.Brands; //All brands (for now)
if(filters.ProductType_Id > 0)
{
//IF the filter has a value, filter the list accordingly:
brands = brands.Where(brand => brand.Products.Any(product => product.TypeId == filters.ProductType_Id);
}
if(filters.ProductWeight_LessThan > 0)
{
//IF the filter has a value, filter the list accordingly:
brands = brands.Where(brand => brand.Products.Any(product => product.Weight < filters.ProductWeight_LessThan));
}
if(!String.IsNullOrWhiteSpace(filters.ProductName_Contains))
{
//IF the filter has a value, filter the list accordingly:
brands = brands.Where(brand => brand.Products.Any(product => product.Name.Contains(filters.ProductName_Contains)));
}
return brands.ToList();
}
This method makes sure that the list was filtered according to the SearchCriteria you provided.
If you didn't use the field filters.ProductName_Contains for example, it would be an empty string, and the if-evaluation would've prevented you from filtering based on an empty string. In the end, you would not have applied a name-based filter.
I hope this is the answer you were looking for? If not, please elaborate more as I'm having trouble understanding what it is you want then.
I have the following entities:
[Table("Entities")]
public abstract class Entity {
public int EntityID { get; set; }
public string Description { get; set; }
public virtual ICollection<Tag> Tags { get; set; }
}
And the Tag Entity:
public class Tag {
public int TagID { get; set; }
public int EntityID { get; set; }
public string TagValue { get; set; }
}
As the above makes sort of clear Tags are not reused just stored as strings. This has made determining whether Entities share tags slightly more difficult (and slow).
I have a working search to return a list of entities in which the entities contain any of the tags:
List<string> searchTags = new List<String> {"test1", "test2"};
entities = (_entityRepository.Entities
.Where(o=>o.Tags.Any(f=>searchTags.Contains(f.TagValue)));
Now I also need to return a list of Entities which contain all of the tags in the list. As a non-property variable cannot be passed into a Contains method I cannot just reverse the order of the call with an all, but this is basically what I am trying to achieve:
entities = (_entityRepository.Entities
.Where(o=>o.Tags.All(f=>f.TagValue.Contains(searchTags)));
I think I have just hit the point where I need to correct the DB schema to re-use Tags which should provide a general performance benefit when filtering my entities on lists of Tags, but I still wanted to ask the following questions:
Am I over complicating this and is there a simple Linq statement which accomplishes this or,
Is this something for which I would should use predicate builder to set my criteria?
This can be done like this:
var query = _entityRepository.Entities.Select(e => e);
query = searchTags.Aggregate(query, (current, tag) => current.Where(e => e.Tags.Any(t => t.TagValue == tag)));
var result = query.ToList();
I want to use RavenDB for a project I am doing, but before I can, I need figure out how to query nested objects... Let me explain
I have a class like this:
public class Customer
{
public string Id { get; set; }
public string Name { get; set; }
public IList<Orders> { get; set; }
}
Then the Order class:
public class Order
{
public int OrderNumber { get; set; }
public decimal OrderAmount { get; set; }
public bool CustomerBilled { get; set; }
}
I create a bunch of fake data and add it to Raven -- some Customers have orders with only CustomerBilled set to true, some with CustomerBilled set to false, and some a mix of true and false on CustomerBilled.
What I need help with, is figuring out how to extract a list of Customers that 1 or more Orders with CustomerBilled set to false.
How would I create a query to do it? I can't seem to get one to work, and I have no idea how.
The dynamic queries in RavenDB can handle this, I think the following should do what you want (sorry I can't compile the code right now to verify)
// List of objects - linq
from doc in Customers
where doc.Orders.Any( order => order.CustomeBilled == false)
select doc;
Edit: on the new link, scroll half way down to the section "more filtering options"
What's the best way to set up a controller to sort by many (possibly null) criteria? Say for example, I was building a site that sold cars. My CarController has a function Index() which returns an IList of cars to the view, and details on each car are rendered with a partial view.
What's the best way to structure this? Especially if there are a lot of criteria: Car Type (aka SUV), Car Brand, Car Model, Car Year, Car Price, Car Color, bool IsNew, or if I want to sort by closest to me etc... I'm using NHibernate as my ORM. Should I have just a ton of possible NHibernate queries and figure out which one to choose based on if/then's in the controller? Or is there a simpler way.
Thanks so much for the help.
I have tasks in my system and created special class for searching:
public class TaskSearchCriteria
{
public List<int> Statuses { get; set; }
public List<int> Severities { get; set; }
public List<int> CreatedBy { get; set; }
public List<int> ClosedBy { get; set; }
public List<int> LastModificationBy { get; set; }
public DateTime? CreationDateFrom { get; set; }
public DateTime? CreationDateTo { get; set; }
public bool SearchInComments { get; set; }
public bool SearchInContent { get; set; }
public bool SearchInTitle { get; set; }
}
One method in that class applies filters:
public IQueryable<Task> Filter(IQueryable<Task> tasks)
{
return
FilterDates(
FilterAssignedTo(
FilterGroups(
FilterOperationSystems(
FilterPlatforms(
FilterPriorities(
FilterSeverities(
FilterVersionsResolved(
FilterVersionsReported(
FilterTaskContent(
FilterStatuses(tasks)))))))))));
}
This is one of methods used for filtering:
private IQueryable<Task> FilterSeverities(IQueryable<Task> tasks)
{
if (Severities.Contains(TaskSearchConsts.All) || (!Severities.Any()))
return tasks;
var expressions = new List<Expression>();
if (Severities.Contains(TaskSearchConsts.Active))
expressions.Add(_taskParameter.EqualExpression("Severity.IsActive", 1));
return tasks.WhereIn(_taskParameter, "Severity.ID", Severities, expressions);
}
This is Entity Framework, but it can be easily done in nHibernate too by adding where clauses to IQuery.
To search I have a method in controller:
[HttpPost]
public ActionResult TaskSearch([Bind(Prefix = "Search")]TaskSearchCriteria criteria)
Having one class for filtering is nice, because it can be serialized and save to database for future use. This way user can reuse filter parameters.
You would have:
public class CarSearchCriteria
{
List<int> ListOfCarTypesIds;
List<int> ListOfCarBrandIds;
bool IsNew;
//and more
}
If list is empty, you don't apply filter.
If you've got a lot of criteria, I find it best to encapsulate in a class rather than passing in lots of action parameters. For example, a project i'm working on at the moment has an action with the following signature:
public claass JobsController : Controller
{
public IList<JobDto> Index(JobSearchCriteria criteria)
{
IList<JobDto> jobs = _jobs.Find(criteria);
//...
}
}
The repository method simply steps through the criteria building up an IQueryable as it goes along. This particular project uses Linq To Sql but the same principal can apply using NHibernates Criteria API (or Linq to NH).
I have the following entity structure:
public class Party
{
public Int32 PartyId { get; set; }
public List<PartyRelationship> RelationShips { get; set; }
}
public class PartyRelationship
{
public Int32 PartyId { get; set; }
public Int32 RelatedPartyId { get; set; }
}
Now if I create a generic list of Party objects, such as List, how can I write a LINQ query against the list that will return all of the PartyRelationship objects that have a relationship to a specific PartyId based on the RelatedPartyId? The LINQ query would need to evaluate the RelatedPartyId of all relationships defined for a Party and compare that against a specific PartyId that I am searching for. When a match is found, I would want that specific PartyRelationship object return in the result. BTW, more than one match can occur.
Can anyone provide some insight into how I could do this?
Any help would be appreciated.
Thanks
Do you mean:
var query = from party in parties // the list
where party.RelationShips != null // overkill???
from related in party.RelationShips
where related.RelatedPartyId == id
select related;