I have the following (kept really simple):
public class Customer
{
public int Id {get; set}
public IEnumerable<Reminder> Reminders {get; set}
public IEnumerable<Order> Orders {get; set}
}
public class Reminder
{
public int CustomerId {get; set}
public string Text {get; set}
}
public class Order
{
public int CustomerId {get; set}
public int CategoryId {get; set}
}
public class OrderDetails
{
public int OrderId {get; set}
public int ProductId {get; set}
}
I'm also using generic repository pattern, and I load entities with nested entities as follows:
public virtual T Get(int id, params Expression<Func<T, object>>[] include)
{
if (include.Any())
{
var set = include.Aggregate<Expression<Func<T, object>>, IQueryable<T>>
(dbset, (current, expression) => current.Include(expression));
return set.SingleOrDefault<T>(x => x.Id == id);
}
return dbset.Find(id);
}
Using Linq, I would like to load a Customer, all his Reminders and all Orders (and their details) having a particular CategoryId. So I'm trying to do like this:
var customer = customerRepository.Get(10, x => x.Reminders, x => x.Orders.Select(o => o.OrderDetails));
But the above loads everything. And if I do the following, an exception is thrown:
var customer = customerRepository.Get(10, x => x.Reminders, x => x.Orders.Where(c => c.CategoryId == categoryId).Select(o => o.OrderDetials));
So how can I actually return only those orders I need?
Related
I am trying to perform the following operation with AutoMapper and don't get the expected result.
I have the following configuration:
public interface IFlatInterface
{
public string A {get; set;}
public string B {get; set;}
public string C {get; set;}
public bool D {get; set;}
}
public class ParentObject
{
public Data X {get; set;}
public Measure Y {get; set;}
}
public class Data
{
public string A {get; set;}
public string B {get; set;}
}
public class Measure
{
public string C {get; set;}
public bool D {get; set;}
}
I have defined the following mapping rules
cfg.CreateMap<IFlatInterface, ParentObject>()
.ForMember(p => p.Measure, o => o.MapFrom(f => f))
.ForMember(p => p.Data, o => o.MapFrom(f => f))
cfg.CreateMap<ParentObject, IFlatInterface>()
.ForMember(i => i.A, o => o.MapFrom(p => p.X.A))
.ForMember(i => i.B, o => o.MapFrom(p => p.X.B))
.ForAllOtherMembers(o => o.MapFrom(p.Y))
The issue is that the value which is populated is a string "p.Measure" for all the remaining fields. I would like to mapping to happen recursively on the members of Measure. I can't put a extensive rule because different classes can implement IFlatInterface.
Any idea on how to achieve this?
Thanks
I have a table that contains 2 foreign key that reference separately to 2 different table.
I would like to return the result of all person that has course of "Science".
How to retrieve the record back using LINQ?
This is what i gotten so far:
return
_ctx.Person
.Include(u => u.Course
.Where(ug=>ug.CourseName== "Science"));
This is not working as it shows the error.
The Include path expression must refer to a navigation property
defined on the type
public class Course
{
public int CourseID {get; set;}
public string CourseName {get; set;}
public virtual ICollection<Person> Persons { get; set; }
}
public class Person
{
public int PersonID {get; set;}
public virtual ICollection<Course> Courses { get; set; }
}
This is the mapping table. Only contains 2 foreign key from 2 different table.
I could not use this table inside the solution.As the code first won't generate this table as it doesn't contain it's own PK.
//This is not shown in the EntityFramework when generating Code First.
public class PersonCouseMap
{
public int PersonID {get; set;}
public int CourseID {get; set;}
}
Update : this works after I switched the entity.
return _ctx.Course
.Include(u=>u.Person)
.Where(ug=>ug.CourseName == "Sciene");
Anyone can explain why it won't work the another way round.
I need to display a List of Person who have course of "Science",
not Course Science that has a list of user.
The original query does not work because you've pushed the Where predicate inside the Include expression, which is not supported as indicated by the exception message.
The Include method is EF specific extension method used to eager load related data. It has nothing to do with the query filtering.
To apply the desired filter person that has course of "Science" you need Any based predicate since the Person.Courses is a collection:
return _ctx.Person
.Where(p => p.Courses.Any(c => c.CourseName == "Science"));
To include the related data in the result, combine it with Include call(s):
return _ctx.Person
.Include(p => p.Courses)
.Where(p => p.Courses.Any(c => c.CourseName == "Science"));
It looks like there is no relations between these two entites, you can establish a relationship by making the following changes to your code:
Here I am assuming that you want to establish Many-to-Many relationship between these two tables by having a third entity PersonCourseMap
public class Course
{
public int CourseID {get; set;}
public string CourseName {get; set;}
public virtual ICollection<CoursePersons> Courses { get; set; }
}
public class Person
{
public int PersonID {get; set;}
public virtual ICollection<PersonCourse> Courses { get; set; }
}
public class PersonCourseMap
{
public int PersonID {get; set;}
public int CourseID {get; set;}
public virtual ICollection<Person> Persons { get; set; }
public virtual ICollection<Course> Courses { get; set; }
}
After making above changes you can simply navigate through properties.
Include Foreign Key Mapping
public class Course
{
public int CourseID {get; set;}
public string CourseName {get; set;}
public virtual ICollection<Person> Person {get; set}
}
public class Person
{
public int PersonID {get; set;}
public virtual ICollection<Course> Course {get; set;}
}
using System.ComponentModel.DataAnnotation.Schema;
public class PersonCouseMap
{
[ForeignKey("Person")]
public int PersonID {get; set;}
[ForeignKey("Course")]
public int CourseID {get; set;}
public virtual ICollection<Person> Person {get; set;}
public virtual ICollection<Course> Course {get; set;}
}
I am using this "model" from a previous question. Here I have a Vehicle,VehicleType, and Price entity.
public class Vehicle
{
public int Id {get; set;}
public string Name {get; set}
public int VehicleTypeId {get; set;}
public virtual VehicleType VehicleType {get; set;}
}
public class VehicleType
{
public int Id {get; set;}
public string VehicleTypeName {get; set}
public ICollection<Vehicle> Vehicles {get; set;}
public ICollection<Price> Prices {get; set;}
}
public class Price
{
public int Id {get; set;}
public int Price {get; set;}
public int VehicleTypeId {get; set;}
public virtual VehicleType VehicleType {get; set;}
}
The VehicleType entity serves as a relationship to both the Vehicle entity and the Price entity. I am trying to use LINQ to get at the Price for a given Vehicle based upon it's VehicleType...
// Query #1 to get `Vehicle` name
var vehicle = dbContext.Vehicles.SingeOrDefault(v => v.Id = 1234);
string vehicleName = vehicle.Name;
// Query #2 to get lowest `Price` for `Vehicle`
var myVehiclePrice = dbContext.Vehicles.Include("VehicleType.Prices")
.SingleOrDefault(v => v.Id == 1234)
.VehicleType.Prices
.OrderBy(p => p.PriceAmount).FirstOrDefault()
I have two queries to get the information I want. Is there a way to combine these two queries together to make one trip to the database? I tried reusing the vehicle variable obtained from the first query, but it represents a single entity and cannot make use of the Include() extension which only works off of an object query.
I think you are misinterpreting the Include. It's used for eagerly loading the entity content. It's not needed at all for queries that use selective projection of entity properties/aggregates.
You can gather the vehicle name and the lowest price with a single database trip simply with
var info = dbContext.Vehicles
.Where(v => v.Id == 1234)
.Select(v => new
{
VehicleName = v.Name,
LowestPrice = v.VehicleType.Prices.Min(p => (int?)p.Price)
})
.SingleOrDefault();
I need to count a list of nested objects, but don't want to return the nested objects.
I have the classes:
public class Categoria
{
public int ID {get; set}
public List<Produto> produto {get; set;}
public int produtoCount {get; set;}
}
public class Produto
{
public ID {get; set}
public string data {get; set;}
}
I have tried using produtoCount in Categoria class, but it only has value when I use a Include of Produto class, like this:
(new Categoria()).AsQueryable().Include(p => p.Produto).ToList();
Is it possible?
Sure it's possible:
DbContext.Categorias
.Where(c => c.Id == id)
.Select(c => new
{
// Assuming you also want the Categoria
Categoria = c,
ProdutoCount = c.produto.Count()
})
.FirstOrDefault();
Please try below code. It may help you.
public class Categoria
{
public int ID {get; set}
private List<Produto> produto {get; set;}
public int produtoCount {get {return produto.Count();} }
}
public class Produto
{
public ID {get; set}
public string data {get; set;}
}
Thanks,
Amit Prajapati
I have the following model:
public class Order
{
public int Id {get; set;}
public int Number {get; set;}
public virtual ICollection<OrderDetail> Details {get; set;}
}
public class OrderDetail
{
public int Id {get; set;}
public int OrderId {get; set;}
public virtual Product Product {get; set;}
}
public class Product
{
public int Id {get; set;}
public int Number {get; set;}
public string Description {get; set;}
}
In my OrderRepository, I load a complete order like this:
public override Order Get(int id)
{
return base.Get(id, x => x.Details);
}
And the base method is:
public virtual T Get(int id, params Expression<Func<T, object>>[] include)
{
if (include.Any())
{
var set = include.Aggregate<Expression<Func<T, object>>, IQueryable<T>>
(dbSet, (current, expression) => current.Include(expression));
return set.SingleOrDefault<T>(x => x.Id == id);
}
return dbSet.Find(id);
}
The above works partially fine because it loads the Order and the OrderDetails. However, I also want to load the related Product for every Detail so that I can display the product description in the list too.
How can I improve on the above method to allow me to do so?
Just add another argument with nested Select:
public override Order Get(int id)
{
return base.Get(id, x => x.Details, x => x.Details.Select(z => z.Product));
}
See MSDN