在ASP.NET EF应用程序中,我有两个具有多对多关系的类。我正在尝试查找所有具有视图中发布的Listings
的{{1}}。类别是视图表单上的复选框。
这些是具有简化的导航属性的类,例如:
Categories
这是我要在我的MVC public class Listing
{
public int ID { get; set; }
public ICollection<Category> Categories { get; set; }
...
}
public class Category
{
public int ID { get; set; }
public ICollection<Listing> Listings { get; set; }
...
}
// this is the join table created by EF code first for reference
public class CategoryListings
{
public int Category_ID { get; set; }
public int Listing_ID { get; set; }
}
中使用的查询,但是它不起作用,我真的不知道该尝试什么:
Controller
在SQL中,我将使用子查询编写该子查询(子查询代表可以搜索的多个类别):
if (model.Categories !=null && model.Categories.Any(d => d.Enabled))
{
List<Listing> itemsSelected = null;
foreach (var category in model.Categories.Where(d => d.Enabled))
{
var itemsTemp = items.Select(x => x.Categories.Where(d => d.ID == category.ID));
foreach (var item1 in itemsTemp)
{
itemsSelected.Add((Listing)item1); //casting error here
}
}
items = itemsSelected;
}
如何使用导航器或lambda在EF中编写该SQL查询? SQL中的子查询将更改每次搜索,并且可以是任何ID。
答案 0 :(得分:1)
Listing/Category
和CategoryListings
之间有关系吗?
这是EF 6的示例:http://www.entityframeworktutorial.net/code-first/configure-many-to-many-relationship-in-code-first.aspx
如果有的话,查询将很简单,就像这样:
CategoryListing.Where(cl => new List<int>{1, 3}.Contains(cl.CategoryRefId))
.Select(x => new {x.ListingRefId, x.CategoryRefId});
如果您需要Listing
或Category
的所有属性,则扩展Include()
会有所帮助。
答案 1 :(得分:1)
您忘记告诉我们您的收藏集items
中包含哪些对象。我认为它们是Listings
。您的情况不起作用,因为itemsTemp
是Categories
的集合,而每个item1
都是Category
,当然不能将其强制转换为{{ 1}}。
建议:要调试投放问题,请替换单词
Listing
与您实际期望的类型。编译器会警告您 类型不正确。还要在lambda表达式中使用适当的标识符。 这使它们更易于阅读
var
稍后我们将返回此代码。
如果我查看您的SQL,似乎您需要以下内容:
我有一个
IQueryable<???> items = ... // collection of Listings? List<Listing> itemsSelected = null; IQueryable<Category> enabledCategories = model.Categories.Where(category => category.Enabled)); foreach (Category category in enabledCategories) { IEnumerable<Category> itemsTemp = items .Select(item => item.Categories .Where(tmpCategory => tmpCategory.ID == category.ID)); foreach (Category item1 in itemsTemp) { // can't cast a Category to a Listing
,至少有DbContext
和Listings
。 我希望所有Categories
及其ID为1或3的Listings
很高兴看到您遵循entity framework code-first conventions,但是您忘记声明了您的收藏集虚拟:
在实体框架中,表中的列由 非虚拟属性。虚拟属性代表关系 在桌子之间。
稍作更改,实体框架即可自动检测到多对多关系。注意Categories
之前的virtual
ICollection
还有class Listing
{
public int ID { get; set; }
// every Listing has zero or more categories (many-to-many)
public virtual ICollection<Category> Categories { get; set; }
...
}
class Category
{
public int ID { get; set; }
// every Category is used by zero or more Listings (many-to-many)
public ICollection<Listing> Listings { get; set; }
...
public bool Enabled {get; set;}
}
DbContext
尽管关系数据库通过联结表实现了多对多关系,但您无需在public MyDbContext : DbContext
{
public DbSet<Listing> Listings {get; set;}
public DbSet<Category> Categories {get; set;}
}
中声明它。实体框架检测到您要设计多对多并为您创建连接表。
但是如何在不访问联结表的情况下执行联接?
答案:不要加入,请使用DbContext
!
Entity Framework知道需要哪些内部联接,并将为您进行联接。
返回您的SQL代码:
请给我所有
ICollections
的所有(或某些)属性,这些属性至少有一个Listings
的ID等于1或3
Category
数据库查询的最慢部分之一是将所选数据从DBMS传输到本地进程。因此,明智的做法是仅转移您实际打算使用的属性。例如,您不需要一对多关系的外键,您知道它等于一对多中var result = myDbcontext.Listings
.Select(listing => new
{ // select only the properties you plan to use
Id = listing.Id,
Name = listing.Name,
...
Categories = listing.Categories
// you don't want all categories, you only want categories with id 1 or 3
.Where(category => category.Id == 1 || category.Id == 3)
.Select(category => new
{
// again select only the properties you plan to use
Id = category.Id,
Enabled = category.Enabled,
...
})
.ToList(),
})
// this will also give you the Listings without such Categories,
// you only want Listings that have any Categories left
.Where(listing => listing.Categories.Any());
部分的ID值。
返回您的代码
在我看来,您的one
是items
。在这种情况下,您的代码希望所有Listings
至少启用了一个Listings
Category