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.
Related
I have a simple test solution which consists of two projects (a 'business' layer and a Data Access layer) using Catel to tie the two together - works fine, no problems.
However, have been reading about how useful AutoMapper can be for helping to move data around such a setup by allowing easy population of DTO's and decided to give it a look...that's when my problems started!
I'm using Entity Framework 6.1, VS 2013 Express for Desktop and accessing a SQL Server Express 14 db - no problems with data retrieval and data displays correctly in my views.
AutoMapper was added using NuGet.
In order to use AutoMapper I've set up the following in my App.xaml.cs
private void InitializeAutomapper()
{
Mapper.CreateMap<Result, ResultDto>();
Mapper.AssertConfigurationIsValid();
}
This code is the first item called inside my 'OnStartup'.
A service in my business layer makes a call to the Data Access layer and retrieves a list of Result entites.
Subsequently, I take a single entity from this list and use that in the AutoMapper mapping call.
I'm trying to populate a resultDTO from this single entity, using the following
Result res = ResultList.First();
ResultDto resultDTO = Mapper.Map<Result, ResultDto>(res);
'res' is correctly populated with data but resultDTO is filled with the default values for the individual data types (in = 0, string = null, DateTime = {01/01/0001 00:00:00}) ie; no values are mapped from the source to the destination.
There are References in both projects to AutoMapper and AutoMapper.Net and no errors are raised - it just doesn't work as advertised...
I'm not slagging off the software, just asking what I'm doing wrong!
I realise there isn't much code to work on here but, in truth, what is posted here is pretty much all I've added to try out AutoMapper. I can see, conceptually how useful it could be - I just need to figure out how to make it happen so any help/comments gratefully received...:)
EDIT
#Andrew, as requested -
Result Class:
public partial class Result
{
public int Div { get; set; }
public System.DateTime Date { get; set; }
public string HomeTeam { get; set; }
public string AwayTeam { get; set; }
public int FTHG { get; set; }
public int FTAG { get; set; }
public string FTR { get; set; }
}
ResultDTO Class:
public class ResultDto
{
int Div { get; set; }
DateTime Date { get; set; }
string HomeTeam { get; set; }
string AwayTeam { get; set; }
int FTHG { get; set; }
int FTAG { get; set; }
string FTR { get; set; }
// Added tonight to try and get it to work
public ResultDto()
{
Div = 0;
Date = DateTime.Now;
HomeTeam = null;
AwayTeam = null;
FTHG = 0;
FTAG = 0;
FTR = null;
}
}
#stuartd, the following is used to retrieve the ResultList from which Result is obtained:
// Produce a list of DataLayer.Result entities.
var ResultList = (from x in dbContext.Results.Local
where x.HomeTeam == team.TeamName.ToString() || x.AwayTeam == team.TeamName.ToString()
orderby x.Date
select x).ToList();
Please note 'team.Teamname' is passed into the above from an external source - seems to be working fine.
So to sum up -
I produce ResultList as a list of Result entities.
Fill Result with the first entity in the list.
Try to map this Result entity to ResultDTO
Fail :(
Hope this helps!
By default, class members are declared private unless otherwise specified so the ResultDto properties aren't visible outside of the class.
public class ResultDto
{
int Div { get; set; }
....
}
needs to be
public class ResultDto
{
public int Div { get; set; }
....
}
AutoMapper can work out the type you are mapping from from the arguments provided. Try this:
ResultDto resultDTO = Mapper.Map<ResultDto>(res);
UPDATE
This is wrong, or at least won't help. We need to see the source and destination classes as mentioned in the comments.
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've got three classes.
Event > Workshop > Workshop Times
I'm currently looking for best way of inserting records into the Workshop Times, this is running through code first using ICollections.
Looking for something along the lines of this, but I know it doesn't work:
//Create connection
var db = new Context();
var Event = db.Events
.Include("Workshops")
.Include("Workshops.Times")
.Where(ev => ev.GUID == EventGUID).FirstOrDefault();
Event.Workshops.Add(new Workshop
{
Name = tbWorkshopName.Text,
Description = tbWorkshopDescription.Text,
Times.Add(new WorkshopTime{
//Information for times
})
});
db.SaveChanges();
Chopped down classes:
public class Workshops{
public int id { get; set; }
public string name { get; set; }
public ICollection<WorkshopTimes> Times{get;set;}
}
public class Events {
public int id { get; set; }
public string name { get; set; }
public ICollection<Workshops> WorkShops { get; set; }
}
public class WorkshopTimes {
public int id { get; set; }
public DateTime time { get; set; }
}
You are definitely on the right track with your query, however your include statements appear incorrect. From your model I would expect:
var Event = db.Events
.Include("WorkShops")
.Include("WorkShops.events")
.Where(ev => ev.GUID == EventGUID).FirstOrDefault();
Note this uses the property names not the types. This will ensure that the entities in the listed nav properties will be included in the result.
In addition you can use a lambda to do the same thing (but its typesafe)
Check out here for how to do a very similar scenario to yours:
EF Code First - Include(x => x.Properties.Entity) a 1 : Many association
or from rowan miller (from EF team)
http://romiller.com/2010/07/14/ef-ctp4-tips-tricks-include-with-lambda/
And make sure you are using System.Data.Entities for lambda based includes ( Where did the overload of DbQuery.Include() go that takes a lambda? )
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"
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))