如何在EF

时间:2018-10-21 22:28:25

标签: c# sql-server entity-framework linq entity-framework-6

在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。

2 个答案:

答案 0 :(得分:1)

Listing/CategoryCategoryListings之间有关系吗? 这是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});

如果您需要ListingCategory的所有属性,则扩展Include()会有所帮助。

答案 1 :(得分:1)

您忘记告诉我们您的收藏集items中包含哪些对象。我认为它们是Listings。您的情况不起作用,因为itemsTempCategories的集合,而每个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 ,至少有DbContextListings。   我希望所有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值。

返回您的代码

在我看来,您的oneitems。在这种情况下,您的代码希望所有Listings至少启用了一个Listings

Category