首页 文章

在Entity Framework中实现与各种表的“连接”

提问于
浏览
0

我有三张桌子:

Materials

  • ID

  • Headers

  • 内容

Likes

  • ID

  • MaterialID

  • UserID

  • IsLiked

Visitors

  • ID

  • UserID

  • MaterialID

  • 日期

  • ReadNow

我想得到一个像这样的对象:

  • Headers

  • 内容

  • CountLikes

  • CountVisitors

我试着做以下事情:

from mat in ctx.materials
let visitors = mat.VisitorsCollection.Where(x=>x.ReadNow).Count()
let likes = mat.LikesCollection.Where(x=>x.IsLiked).Count()
let iliked = mat.LikesCollection.Where(x=>x.UserID == myID && x.IsLiked).Any()
select new {
   Material = mat,
   Visitors = visitors,
   Likes = likes,
   Liked = iliked
}

我获得了一些材料,并且实体框架分别接收了访问者数量等数据 .

我也尝试了以下内容:

from mat in ctx.materials
join lik in ctx.Likes.Where(x=>x.UserID == myID && x.IsLiked) on map.ID equals lik.MaterialID 
select new {
   Material = mat,
   Liked = lik.Any()
}

但现在出现错误:

Microsoft.EntityFrameworkCore.Query:警告:LINQ表达式'Any()'无法翻译,将在本地进行评估 .

2 回答

  • 3

    好吧,如果你在数据库中有外键,那么EF会在对象之间生成链接,所以你需要做的就是:

    var result = ctx.materials.Select(x => 
         new SomeClass{
              Material = x,
              Visitors = x.Visitors.Where(v => v.ReadNow).Count(),
              Likes = x.Likes.Where(y => y.IsLiked).Count(),
              Liked = x.Likes.Where(z => z.IsLiked && z.UserID == myID).Count()
         }).ToList();
    

    语法可能并不完全正确,但你明白了......

  • 0

    如果您使用的是实体框架,请考虑使用ICollections,而不是自己执行连接 .

    你有一个 Materials 的序列,其中每个 Material 都有零个或多个 Likes 和零个或多个 Visitors ,两个一对多的关系,使用 Material 的外键 .

    如果您已经按照entity framework code first conventions进行操作,那么您将拥有类似于以下内容的类

    class Material
    {
         public int Id {get; set;}
         public string Title {get; set;}
         public string Content {get; set;}
    
         // every Material has zero or more Likes (one-to-many)
         public virtual ICollection<Like> Likes {get; set;}
    
         // every Material has zero or more Visitors (one-to-many)
         public virtual ICollection<Visitor> Visitors {get; set;}
    }
    

    喜欢和访客:

    class Like
    {
         public int Id {get; set;}
         public bool IsLiked {get; set;}
         ...
    
         // every Like belongs to exactly one Material, using foreign key
         public int MaterialId {get; set;}
         public virtual Material Material {get; set;}
    }
    
    class Visitor
    {
         public int Id {get; set;}
         ...
    
         // every Visitor belongs to exactly one Material, using foreign key
         public int MaterialId {get; set;}
         public virtual Material Material {get; set;}
    }
    

    这就是实体框架需要检测一对多关系的所有内容 . 可能是您需要不同的表名称或列的不同标识符 . 在这种情况下,需要属性或流畅的API

    在实体框架中,表的列由非虚拟属性表示 . 虚拟属性表示表之间的关系(一对多,多对多等)

    一旦正确获得了类定义,您的查询就会非常简单直观:

    需求:

    从我的材料集合中,从每个材料, Headers ,内容,喜欢的数量以及它拥有的访客数量中提供给我:

    var result = myDbContext.Materials
       .Where(material => ...)            // only if you don't want all Materials
       .Select(material => new            // from every Material make one new object
       {                                  // containing the following properties
           Title = material.Title,
           Content = material.Content,
    
           // if you want any information of the likes of this material, use property Likes
           LikeCount = material.Likes
               .Where(like => like.IsLiked)  // optional, only if you don't want all likes
               .Count(),
           NrOfVisitors = material.Visitors
               .Where(visitor => ...)        // only if you don't want all visitors
               .Count(),
       });
    

    用文字表示:从我完整的材料集合中,只保留那些......从每个剩余的材质中创建一个新对象:

    • Headers 是材料的 Headers

    • 内容是材料的内容

    • LikeCount是此材料的喜欢数量(具有真正的IsLiked)

    • NrOfVisitors是此材料的访客数量(即...)

    实体框架知道您的关系,并知道需要GroupJoin .

相关问题