Add list of items using linq - c#

I have a class that holds Categories.
public class CategoryDto
{
public int Id { get; set; }
public int PortfolioId { get; set; }
public string Description { get; set; }
public List<SubCategoryDto> SubCategories { get; set; }
public CategoryDto()
{
SubCategories = new List<SubCategoryDto>();
}
}
It has a List in it, which is a list of SubCategory classes:
public class SubCategoryDto
{
public int Id { get; set; }
public int CategoryId { get; set; }
public CategoryDto Category { get; set; }
public string Description { get; set; }
}
I then populate this item, but I am getting a list bases on a 'PortfolioId'.
var cats = (from p in Context.transaction_category
where p.account_portfolio_id == portfolioId
&& p.deleted == null
select new CategoryDto
{
Id = p.id,
Description = p.description,
PortfolioId = p.account_portfolio_id
}).ToList();
The Categories table has a foreign key to SubCategories. Each category has 0:n sub categories. So, the entity framework model has a Context.transaction_category.transaction_sub_categories collection.
So now what I do is, foreach through the categories in the list above, and populate the sub categories.
Is there a way to do this in the same link statement? The Categories object has a List list. Can it be done in the above Linq statement?
Edit:
This is the fix attempt, as recommended, but is presenting an error:
var cats = (from p in Context.transaction_category
where p.account_portfolio_id == portfolioId
&& p.deleted == null
select new CategoryDto
{
Id = p.id,
Description = p.description,
PortfolioId = p.account_portfolio_id,
SubCategories = (from s in Context.transaction_sub_category where s.transaction_category_id == p.id
&& s.deleted == null
select new SubCategoryDto
{
Id = s.id,
Description = s.description,
CategoryId = s.transaction_category_id
}).ToList()
}).ToList();
LINQ to Entities does not recognize the method
'System.Collections.Generic.List1[Objects.SubCategoryDto]
ToList[SubCategoryDto](System.Collections.Generic.IEnumerable1[Objects.SubCateg‌​oryDto])'
method, and this method cannot be translated into a store expression.

You can do it like this:
var cats = (from p in Context.transaction_category
where p.account_portfolio_id == portfolioId
&& p.deleted == null
select new CategoryDto
{
Id = p.id,
Description = p.description,
PortfolioId = p.account_portfolio_id,
SubCategories = (from s in Context.transaction_category.transaction_sub_categories
where s.CategoryId == p.Id
select new SubCategoryDto {
Id = s.Id,
Description = s.Decription
}).ToList()
}).ToList();
Update: To make it easier change your SubCategories and Category properties like this:
public virtual List<SubCategoryDto> SubCategories { get; set; }
public virtual CategoryDto Category { get; set; }
Then you can use include and simply load your sub categories like this:
var cats = Context.transaction_category
.Where(p => p.account_portfolio_id == portfolioId && p.deleted == null)
.Include(p => p.SubCategories);

Related

Hierarchical select in Entity Framework with lambda expression

I have a relational dataset as dummy. I want to take the data as hierarchical (Role > SubRoles > Permissions) then I will convert to JSON but I get an exception:
Error CS0266
Cannot implicitly convert type 'System.Collections.Generic.IEnumerable' to 'System.Collections.Generic.List'. An explicit conversion exists (are you missing a cast?)
Thanks for your answer.
Model classes:
public class Role
{
public int Id { get; set; }
public string Name { get; set; }
public List<SubRole> SubRoles { get; set; }
}
public class SubRole
{
public int Id { get; set; }
public string Name { get; set; }
public string EndPoint { get; set; }
public List<Permission> Permissions { get; set; }
}
public class RoleSubRole
{
public int Id { get; set; }
public int RoleId { get; set; }
public int SubRoleId { get; set; }
}
public class Permission
{
public int Id { get; set; }
public string Name { get; set; }
}
public class SubRolePermission
{
public int Id { get; set; }
public int SubRoleId { get; set; }
public int PermiisonId { get; set; }
}
public class RoleModel
{
public Role Role { get; set; }
}
Program class:
public static void Main(string[] args)
{
RoleModel roleModel = new RoleModel()
{
Role =
(from u in DataSet.Users
join r in DataSet.Roles on u.RoleId equals r.Id
where u.Id == 1
select new Role
{
Name = r.Name,
SubRoles =
(from rsb in DataSet.RoleSubRoles
join sr in DataSet.SubRoles on rsb.SubRoleId equals sr.Id
where r.Id == rsb.RoleId
select new SubRole
{
Name = sr.Name,
EndPoint = sr.EndPoint,
Permissions =
(from srp in DataSet.SubRolePermissions
join p in DataSet.Permissions on srp.PermiisonId equals p.Id
where srp.SubRoleId == sr.Id
select new Permission
{
Name = p.Name
})
})
})
};
}
You should use
Permissions =
(from srp in DataSet.SubRolePermissions
join p in DataSet.Permissions on srp.PermiisonId equals p.Id
where srp.SubRoleId == sr.Id
select new Permission
{
Name = p.Name
}).ToList()
The Permissions is a List<T>, while the query returns an IEnumerable<T>. Same is the case with SubRoles.You need to convert to List<T>, which could be done using the ToList() method
Complete Query
Role =
(from u in DataSet.Users
join r in DataSet.Roles on u.RoleId equals r.Id
where u.Id == 1
select new Role
{
Name = r.Name,
SubRoles =
(from rsb in DataSet.RoleSubRoles
join sr in DataSet.SubRoles on rsb.SubRoleId equals sr.Id
where r.Id == rsb.RoleId
select new SubRole
{
Name = sr.Name,
EndPoint = sr.EndPoint,
Permissions =
(from srp in DataSet.SubRolePermissions
join p in DataSet.Permissions on srp.PermiisonId equals p.Id
where srp.SubRoleId == sr.Id
select new Permission
{
Name = p.Name
}).ToList()
}).ToList()
}).First()
};
Also note that the Role represents a single entity, while the query returns a collection. You need to make a choice on which entity from the collection needs to be stored. For the sample code above, I have used First()

categories and sub-categories in c# / linq & sql

I am building an asp.net website with ms-sql db for products - each product belongs to one or more categories and each categories can belong to one or zero parent categories.
The user should be able to select zero or many categories, but i can't figure out a way to only return products in the selected categories.
i've got other filters which are working (minimum price, brand name etc) but cant' get the categories to work.
For example:
-Category 1
|---Sub-Category 1.1
|---Sub-Sub-Category 1.1.1
|---Sub-Sub-Category 1.1.2
|---Sub-Category 1.2
|---Sub-Category 1.3
If Category 1 is selected, then all products that have a category where the Ultimate Parent is Category 1 should be returned.
If Sub-Category 1.1 and Sub-Category 1.2 is selected then all products that have a category where the Ultimate Parent is either Sub-Category 1.1 OR Sub-Category 1.2 should be returned.
This is my Code:
Product:
public class Product
{
[Key]
public int ProductID { get; set; }
public string Description {get;set;}
public double Price {get;set;}
public virtual List<Category> Categories { get; set; }
public Product()
{
Categories = new List<Category>();
}
}
Category:
public class Category
{
[Key]
public int CategoryID { get; set; }
public string CategoryName { get; set; }
public int? ParentCategoryID { get; set; }
[JsonIgnore]
public Category Parent { get; set; }
[JsonIgnore]
public virtual List<Product> Products { get; set; }
}
Simplified WebApi Controller:
public object Get( [FromUri] string[] categories)
{
List<Product> search_results = (from p in db.Products
where 1==1
&& p.Price >= minPrice && p.Price <=maxPrice
// only return products in selected categories
select p).ToList();
}
If you have no limits on sub categories, you can use recursion:
public object Get( [FromUri] string[] categories)
{
var categories = db.Categories.Where(c => categoriesIds.Contains(c.Id));
Func<Product, bool> filters = p => 1==1
&& p.Price >= minPrice && p.Price <=maxPrice
return GetCategoryiesProducts(categories, filters)
}
public IList<Product> GetCategoryiesProducts(IList<Category> categories, Func<Product, bool> filters)
{
var result = new List<Product>();
foreach (var c in categories)
{
result.AddRange(c.Products.Where(filters).ToList());
var subCategories = db.Categories.Where(s => s.ParentCategoryID != null && (int)s.ParentCategoryID == c.Id))
if (subCategories != null && subCategories.Count > 0)
{
result.AddRange(GetCategoryiesProducts(subCategories, filters))
}
}
List<Product> search_results result;
}
but if there be a lot of categories it will be expensive solution. To optimize for efficiency you can add product to each parent categories to eliminate recursion:
List<Product> search_results = (from p in db.Products
where 1==1
&& p.Price >= minPrice && p.Price <=maxPrice
&& p.Categories.Any(c => categoriesIds.Contains(c.Id))
select p).ToList();

traversing one to many relationships in entity framework

I am having trouble figuring out how to traverse a one to many relasionship using LINQ-To-SQL in my asp.net site that uses EF 5. I have made the relationships in the class files but when I try to go from parent to child in my where clause I am not given a list of the child columns to filter on. Can anyone tell me what is wrong with my code, I am new to EF and LINQ.
Product.cs:
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public virtual Category Category { get; set; }
}
}
Category.cs:
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
public virtual IList<Product> Products { get; set; }
}
Codebehind:
using (var db = new Compleate())
{
rpBooks.DataSource = (from c in db.Categories
where c.Products.Name == "Books"
select new
{
c.Name
}).ToList();
}
Do you want all products in the books category?
from p in db.Products
where p.Category.Name == "Books"
select new
{
p.Name
}
Or do you want to have all categories that contain products that are called called books?
from c in db.Categories
where c.Products.Contains( p => p.Name == "Books")
select new
{
c.Name
}
BTW, if you're only selecting the name, you can skip the anonymous type in the select part...
select p.name
Ok I had to update the codebhind to look like:
using (var db = new Compleate())
{
rpBooks.DataSource = (from c in db.Categories
join p in db.Products on c.ID equals p.id
where c.Products.Name == "Books"
select new
{
c.Name
}).ToList();
}
It should be name = c.Name it's not an issue with traversing, it's an issue with syntax, read the brief article on anonymous types here

Given a list of items, each containing a subitem, get the subitems and remove duplicates

Given a list of groupos, where each groupo has a single empresa and multiple groupos can have the same empresa, how do you get the empresas that contain any of the list's groupos?
I have this Model:
public class Grupo
{
public int id { get; set; }
public string descripccion { get; set; }
[ForeignKey("Empresas")]
public int empresa { get; set; }
public virtual empresa Empresas { get; set; }
}
public class empresa
{
public int id { get; set; }
public string descripcion { get; set; }
public virtual ICollection<Grupo> Grupos { get; set; }
}
So this method gives me a List
private List<Grupo> VerEmpresas(int userId)
{
var lista = (from ga in db.GrupoAccesos
join g in db.Grupos
on ga.grupo equals g.id
where ga.usuario == userId
select g).ToList();
return lista;
}
and now I want to use this method to show me the empresas that are related to grupo.
Below emp gives a bool, and instead I want all the empresas that are in my list of grupos.
List<Grupo> verEmpresa = VerEmpresas(1);
var emp = (from p in db.Empresas
select p.Grupos).Contains(verEmpresa);
ViewBag.empresa = new SelectList(emp, "id", "descripcion");
You can try getting the empresa ids from your Grupo list and using the foreign key relationship to get the empresas:
var empresaIds = verEmpresa.Select( v => v.empresa ).Distinct().ToList();
var emp = from p in db.Empresas
where empresaIds.Contains( p.id )
select p;
In your code you are passing 'VerEmpresa' which is a list of Grupo. You should pass one object of Grupo from that list. Try using Any and All method on verEmpresa List.
Try something like:
from p in db.Empresas
where verEmpresa.Any(val => p.Contains(val))
select p;
If all you want is the empresas, try:
var emp = (from e in db.Empresas
from g in db.Grupos
where e.Grupos.Contains(g)
select e);

EFv1 mapping 1 to many Relationship to POCOs

I'm trying to work through a problem where I'm mapping EF Entities to POCO which serve as DTO.
I have two tables within my database, say Products and Categories. A Product belongs to one category and one category may contain many Products. My EF entities are named efProduct and efCategory. Within each entity there is the proper Navigation Property between efProduct and efCategory.
My Poco objects are simple
public class Product
{
public string Name { get; set; }
public int ID { get; set; }
public double Price { get; set; }
public Category ProductType { get; set; }
}
public class Category
{
public int ID { get; set; }
public string Name { get; set; }
public List<Product> products { get; set; }
}
To get a list of products I am able to do something like
public IQueryable<Product> GetProducts()
{
return from p in ctx.Products
select new Product
{
ID = p.ID,
Name = p.Name,
Price = p.Price
ProductType = p.Category
};
}
However there is a type mismatch error because p.Category is of type efCategory. How can I resolve this? That is, how can I convert p.Category to type Category?
Likewise when I do
return from c in ctx.Categories
where c.ID == id
select new Category
{
ID = c.ID,
Name = c.Name,
ProductList = c.Products;
};
I get a mismatch because ProductList is of type Product, where c.Products is an EntityCollection
I know in .NET EF has added support for POCO, but I'm forced to use .NET 3.5 SP1.
return from p in ctx.Products
select new Product
{
ID = p.ID,
Name = p.Name,
Price = p.Price
ProductType = new Category
{
ID = p.Category.ID,
Name = p.Category.Name // etc.
}
};
For Category you do:
return from c in ctx.Categories
where c.ID == id
select new Category
{
ID = c.ID,
Name = c.Name,
ProductList = from p in c.Products
select new Product
{
ID = p.ID,
Name = p.Name,
Price = p.Price
}
};

Categories

Resources