EntityFrameWork Core从零开始,(八)数据查询

前言:
EFCore的查询方式有几种,
查询的API是比较简单的,
至少不用像原生的ADO.NET那样,需要执行SQL后手动把结果从一张DataTable中设置到数据模型中
这里只讲几种常见的查询方式,
如需了解EFCore数据查询的原理,可以参考文档
https://docs.microsoft.com/zh-cn/ef/core/querying/how-query-works

1.数据库上下文查询

这里用之前的一个多对多的例子来看

class StudentCopy
{
    public int id { get; set; }
    public string name { get; set; }

    public int age { get; set; }
    public ICollection<Course> courses { get; set; }

    public StudentCopy()
    {
        courses = new List<Course>();
    }
}
class Course
{
    public int id { get; set; }

    public string course_name { get; set; }
    public string teacher_name { get; set; }
    public ICollection<StudentCopy> students { get; set; }
    public Course()
    {
        students = new List<StudentCopy>();
    }
}
class MMDbContext:DbContext
    {
        public DbSet<Course> courses { get; set; }
        public DbSet<StudentCopy> studentCopies { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            var Connection = "server=.;Database=EFCoreTest;uid=sa;pwd=LiHan199968";
            optionsBuilder.UseSqlServer(Connection);
            //optionsBuilder.LogTo(Console.WriteLine,LogLevel.Debug);   
        }
    }

现有数据如下:

//表 studentCopies
id | name | age
 1 | 罗翔 | 21
 2 | 孙笑川 | 99
 //表 courses
 id | course_name | teacher_name
 1 | 張三說刑法 | 張三
 2 | 這把怎麼輸 | 盧本偉
 2 | 李四說民法 | 李四
 //中间表 CourseStudentCopy
  course_id | student_id
   1 | 1 
   2 | 1 
   1 | 2 
   2 | 2
   3 | 2 
一.查询实体

1.直接在DbContext中维护的跟踪对象中查找(就是在你定义的那个集合中Find)
PS:Find方法的参数都是实体的主键类型数据

static void Main(string[] args)
 {
     MMDbContext context = new MMDbContext();
     StudentCopy luoxiang =  context.studentCopies.Find(1);
     Console.WriteLine("ID:"+luoxiang.id+"姓名:" + luoxiang.name + "年齡:" + luoxiang.age );
 }

结果:

ID:1姓名:羅翔年齡:21

当然你也可以直接在DbContext上调用Find方法(需指定类型,不然可能会有歧义)

static void Main(string[] args)
{
    MMDbContext context = new MMDbContext();
    StudentCopy luoxiang =  context.Find<StudentCopy>(1);
    Console.WriteLine("ID:"+luoxiang.id+"姓名:" + luoxiang.name + "年齡:" + luoxiang.age );
}

当然:这里如果你想问为什么不输出关联属性的值,这是因为DbContext默认是懒加载的,即不主动加载关联对象的属性
我们也可以试试看

static void Main(string[] args)
{
     MMDbContext context = new MMDbContext();
     StudentCopy luoxiang =  context.Find<StudentCopy>(1);
     Console.WriteLine("ID:"+luoxiang.id+"姓名:" + luoxiang.name + "年齡:" + luoxiang.age + "選課" +luoxiang.courses.Count );
 }

结果:

ID:1姓名:羅翔年齡:21選課0
//数据库上下文查找并不查询关联属性

如果你想要查询它的关联属性,你需要再写一条显式查找的语句

static void Main(string[] args)
{
    MMDbContext context = new MMDbContext();
    StudentCopy luoxiang = context.studentCopies.Find(1);
    context.Entry(luoxiang).Collection<Course>(stu=>stu.courses).Load();
    Console.WriteLine("ID:"+luoxiang.id+"姓名:" + luoxiang.name + "年齡:" + luoxiang.age + "選課" +luoxiang.courses.Count );
}

结果:

ID:1姓名:羅翔年齡:21選課2
//这样就可以查询出它的关联属性了
二.查询属性(少用)

在对象跟踪的前一章中,我们提到了EntityEntry对象就是一个实体的包装类,可以在里面拿到跟踪信息等等…可以在其中获取实体的属性详情(一般查属性可以直接在对象里拿,不需要使用EntityEntry的API)

static void Main(string[] args)
{
    //注意:属性查询不能查询导航字段
    MMDbContext context = new MMDbContext();
    StudentCopy luoxiang = context.studentCopies.Find(1);
    var pv =  context.Entry(luoxiang).Property(stu=>stu.age);
    Console.WriteLine(pv.CurrentValue);
}

2.构造LINQ表达式查询

LINQ查询是C#的一种语言标准,
用于集合类型和数据库查询
在EFCore中推荐使用LINQ查询
LINQ的详细用法可以参考码友网的教程:
码友网LINQ教程

static void Main(string[] args)
{
    MMDbContext context = new MMDbContext();
    //使用Include可以预先加载实体的关联属性,如果不是用也不会加载关联属性
    StudentCopy luoxiang = context.studentCopies.Include(stu=>stu.courses)
                                                 .Where(stu=>stu.age <= 100)
                                                  .OrderBy(stu=>stu.id)
                                                   .Distinct()
                                                    .First();
    Console.WriteLine("ID:" + luoxiang.id + "姓名:" + luoxiang.name + "年齡:" + luoxiang.age);
    foreach(var course in luoxiang.courses)
    {
        Console.WriteLine("所選課程ID:" + course.id + "課程名:" + course.course_name + "課程教師:"+ course.teacher_name);
    }

}

结果:

ID:1姓名:羅翔年齡:21
所選課程ID:1課程名:張三說刑法課程教師:張三
所選課程ID:2課程名:這把怎麼輸課程教師:盧本偉

如果不想写过多的Include,你也可是自动设置加载关联(FluentAPI)

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
     //设置自动加载盗汗属性
    modelBuilder.Entity<StudentCopy>().Navigation(stu=>stu.courses).AutoInclude();
}

当然如果以个实体的关联属性也包含其他关联属性,也不可传递使用ThenInclude()

using (var context = new BloggingContext())
{
    var blogs = context.Blogs
        .Include(blog => blog.Posts)
        .ThenInclude(post => post.Author)   //加载关联属性的关联属性
        .Include(blog => blog.Posts)
        .ThenInclude(post => post.Tags)     //分两次加载
        .ToList();
}
using (var context = new BloggingContext())
{
    var blogs = context.Blogs
        .Include(blog => blog.Owner.AuthoredPosts)
        .ThenInclude(post => post.Blog.Owner.Photo)   //一次加载关联属性的两个关联属性
        .ToList();
}

同时也可以对关联属性进行LINQ查找,在官网中叫做筛选包含

using (var context = new BloggingContext())
{
    var filteredBlogs = context.Blogs
        .Include(
            blog => blog.Posts
                .Where(post => post.BlogId == 1)
                .OrderByDescending(post => post.Title)
                .Take(5))
        .ToList();
}

3.原生SQL查询

可以把查询方法下调到原生SQL上,用于SQL查询或执行存储过程
它主要有两种方法
1.FromSqlRow(String sql,params…)
在串外指定参数

var user = "johndoe";

var blogs = context.Blogs
    .FromSqlRaw("EXECUTE dbo.GetMostPopularBlogsForUser {0}", user)
    .ToList();
var user = new SqlParameter("user", "johndoe");
var blogs = context.Blogs
    .FromSqlRaw("EXECUTE dbo.GetMostPopularBlogsForUser @user", user)
    .ToList();

2.FromSqlInterpolated(String sql)
串内指定参数

var user = "johndoe";

var blogs = context.Blogs
    .FromSqlInterpolated($"EXECUTE dbo.GetMostPopularBlogsForUser {user}")
    .ToList();
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

罗马苏丹默罕默德

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值