Entity Framework Core执行SQL聚合查询

尽管EF Core功能强大,但是仍然存在EF Core生成的SQL语句无法正确执行的情况。因此在少数场景下,仍然需要在EF Core中执行原生SQL语句。

1. EF Core无法正常执行的个例

1.1 数据表结构

Rains表存放降水数据,数据库为mysql,每小时一条记录,每5分钟更新一次数据。小时雨量存放在RF,逐5分钟雨量分别存放在RF1、RF2...RF12。RecTime记录整点时间(如2023-11-1 20:00:00),AMinute记录最后更新的分钟刻度(如5、10)。创建表的SQL语句如下:

create table Rains
(
    QuZhanHao int      not null,
    RecTime   datetime not null,
    AMinute   tinyint  not null,
    RF        smallint not null,
    RF1       smallint not null,
    RF2       smallint not null,
    RF3       smallint not null,
    RF4       smallint not null,
    RF5       smallint not null,
    RF6       smallint not null,
    RF7       smallint not null,
    RF8       smallint not null,
    RF9       smallint not null,
    RF10      smallint not null,
    RF11      smallint not null,
    RF12      smallint not null,
    primary key (QuZhanHao, RecTime)
);

1.2 EF Core实体类配置

Rain实体类

public class Rain
{
    public int QuZhanHao { get; set; }

    public DateTime RecTime { get; set; }

    public byte AMinute { get; set; }

    public short RF { get; set; }

    public short RF1 { get; set; }

    public short RF2 { get; set; }

    public short RF3 { get; set; }

    public short RF4 { get; set; }

    public short RF5 { get; set; }

    public short RF6 { get; set; }

    public short RF7 { get; set; }

    public short RF8 { get; set; }

    public short RF9 { get; set; }

    public short RF10 { get; set; }

    public short RF11 { get; set; }

    public short RF12 { get; set; }

    public Rain() { }
}

实体类与数据库映射,使用Fluent API进行配置

public class ApplicationDbContext : IdentityDbContext
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
    : base(options)
    {
    }

    public DbSet<Rain> Rains { get; set; }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        builder.Entity<Rain>().ToTable("Rains");
        builder.Entity<Rain>().HasKey(r => new { r.QuZhanHao, r.RecTime });

        base.OnModelCreating(builder);
    }
}

1.3 查询需求

现在要获得Rains表最后更新的时间,于是用C#编写EF Core查询代码如下

//_context为依赖注入的ApplicationDbContext
_context.Rains.Max(x => x.RecTime.AddMinutes(x.AMinute))

结果出现如下错误

MySqlConnector.MySqlException (0x80004005): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'double) AS signed) minute))

EF Core生成的SQL语句如下,无法正确执行

SELECT MAX(DATE_ADD(`r`.`RecTime`, INTERVAL CAST(CAST(`r`.`AMinute` AS double) AS signed) minute))
      FROM `Rains` AS `r`

2. EF Core中执行原生SQL语句

为了解决这个问题,尝试让EF Core执行原生SQL语句。EF Core似乎不能直接将SQL聚集查询结果直接转为基本类,例如将Max(RecTime)的SQL查询结果转为C#的DateTime。这里先创建一个实体模型,然后进行映射配置,最后再从数据集(DbSet<LastUpdate> LastUpdates)中获得查询结果。步骤如下:

2.1 创建映射实体

用record类型的LastUpdate进行映射

    public record LastUpdate(DateTime LastRecTime);

2.2 在ApplicationDbContext中进行映射配置

 添加 DbSet<LastUpdate>,添加SQL查询映射,修改后的代码如下:

public class ApplicationDbContext : IdentityDbContext
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
    : base(options)
    {
    }

    public DbSet<Rain> Rains { get; set; }

    public DbSet<LastUpdate> LastUpdates { get; set; }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        builder.Entity<Rain>().ToTable("Rains");
        builder.Entity<Rain>().HasKey(r => new { r.QuZhanHao, r.RecTime });

        builder.Entity<LastUpdate>().ToSqlQuery("select max(date_add(rectime,interval AMinute minute)) as LastRecTime from Rains");
        builder.Entity<LastUpdate>().HasNoKey();

        base.OnModelCreating(builder);
    }
}

2.3 获取聚合查询结果

 聚合查询的结果只有一个,因此从List<LastUpdate>中取第一个值,C#代码如下:

//_context为依赖注入的ApplicationDbContext
DateTime rainLastUpdate=_context.LastUpdates.First().LastRecTime;

经过这番操作后,终于得到正确的结果。检查EF Core生成的SQL代码,正是前面编写的原生SQL代码:

SELECT `v`.`LastRecTime`
FROM (
    select max(date_add(rectime,interval AMinute minute)) as LastRecTime from Rains
) AS `v`
LIMIT 1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你可以使用 Entity Framework 来操作 SQL Server 数据库。Entity Framework 是一个对象关系映射(ORM)框架,它可以帮助你通过代码来操作数据库,而不需要直接编写 SQL 查询语句。 首先,你需要安装 Entity Framework。你可以在 Visual Studio 的 NuGet 包管理器中搜索并安装 Entity Framework 相关的包。 接下来,你需要定义一个数据上下文(DbContext)类,该类表示数据库中的一组实体(表)。你可以在数据上下文类中定义 DbSet 属性,每个 DbSet 属性对应一个实体的集合。 然后,你可以使用 LINQ 查询语法来查询和操作数据库。Entity Framework 会将 LINQ 查询转换为相应的 SQL 查询语句,并执行在数据库中。 下面是一个简单的示例: ```csharp // 创建数据上下文类 public class MyDbContext : DbContext { public DbSet<Customer> Customers { get; set; } // 其他实体的 DbSet 属性 } // 定义实体类 public class Customer { public int Id { get; set; } public string Name { get; set; } // 其他属性 } // 使用数据上下文类操作数据库 using (var context = new MyDbContext()) { // 查询数据 var customers = context.Customers.Where(c => c.Name.StartsWith("John")).ToList(); // 插入数据 var customer = new Customer { Name = "John Smith" }; context.Customers.Add(customer); context.SaveChanges(); // 更新数据 customer.Name = "John Doe"; context.SaveChanges(); // 删除数据 context.Customers.Remove(customer); context.SaveChanges(); } ``` 这只是一个简单的示例,你可以根据具体的需求进一步学习和使用 Entity Framework 操作 SQL Server 数据库。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值