<Entity Framework> - 直接执行数据库命令

介绍了如何在Entity Framework 4.1及以上版本中执行原生SQL查询和非查询命令,包括通过DbSet.SqlQuery获取实体对象集、通过Database.SqlQuery获取非实体对象集以及通过Database.ExecuteSqlCommand执行非查询SQL命令。

原文地址: http://msdn.microsoft.com/en-us/library/gg715124(v=vs.103)

 

使用 EF 4.1 或者更新版本, 你可以直接执行任何数据库命令. 在本节介绍的方法允许你对数据库执行原生的 SQL 命令.

 

通过 SQL 查询语句获取实体对象集

DbSet 类中的 SqlQuery 方法允许你执行一个返回实体对象集的原生 SQL 查询. 默认情况下, 返回的对象集会被上下文跟踪; 这可以通过对方法返回的 DbSqlQuery 对象调用AsNoTracking 方法取消.返回的结果集一般为 DbSet 所对应的类型, 否则即便是其派生类也无法返回. 如果所查询的表包含了其他实体类型的数据, 那么所执行的 SQL 语句应该被正确书写, 保证只返回指定类型实体的数据. 下面的例子使用 SqlQuery 方法执行了一个 SQL 查询, 返回一个 Department 类型的实例集.

1 using (var context = new SchoolEntities()) 
2 { 
3     var departments = context.Departments.SqlQuery( 
4                     "select * from Department").ToList(); 
5 }

译注: AsNoTracking 方法必须再查询执行前调用, 查询执行后调用无效.

通过 SQL 查询获取非实体对象集

通过 Database 类中的 SqlQuery 方法来执行原生 SQL 命令, 可以返回任何类型的实例, 包括 .Net 中的原生类型. 但获取的数据将不会被上下文对象跟踪, 即使我们用这个方法来检索实体对象. 如:

1 using (var context = new SchoolEntities()) 
2 { 
3     var names = context.Database.SqlQuery<string>("select Name from Department").ToList(); 
4 } 

让数据库执行原生的非查询 SQL 命令

可以通过 Database 类中的 ExecuteSqlCommand 方法执行非查询命令. 例如:

1 using (var context = new SchoolEntities()) 
2 { 
3     context.Database.ExecuteSqlCommand("update Department set Name = 'Mathematics' where Name = 'Math'"); 
4 }

ExecuteSqlCommand 方法有时会被用在 Code First 创建的数据库的初始化函数中, 用来对数据库进行一些额外的配置 (例如, 设置索引). 需要注意的是, 上下文对象并不知道执行了ExecuteSqlCommand 方法后数据库中的数据有什么改变, 除非你从数据库中载入或重新载入实体集.

调用存储过程

Code First 并不支持对存储过程的映射. 但是, 你可以通过 ExecuteSqlCommand 或 SqlQuery 方法直接调用存储过程. 例如: context.Database.ExecuteSqlCommand ("EXECUTE [dbo].[DoSomething]").

译注: 本文提到的三个方法 (DbSet.SqlQuery, Database.SqlQuery, Database.ExecuteSqlCommand) 都支持参数化查询, 用法和 string.Format 类似, 但是在查询执行时会对传入的参数进行类型转换. 如: context.Departments.SqlQuery("select * from Department where DepartmentID = {0}", "6"); 该语句执行时, 会将字符串 "6" 转化为整数然后再代入查询语句中执行, 可以有效防止 SQL 注入.

防止 SQL 注入攻击

应用程序经常要从外部获取输入 (来自用户和其他外部代理) , 然后根据这些输入执行相关操作. 从用户或外部代理直接或间接获取的任何信息都可能利用目标程序语言的语法来执行违法操作. 当目标语言是结构化查询语言 (SQL) 时, 例如 Transact-SQL, 这个操作被称为 SQL 注入攻击. 恶意的用户可以直接在查询中注入命令执行操作, 删除数据库中的一个表, 拒绝提供服务或修改正在执行的操作的性质. 故你应该使用参数化的查询, 而不是直接将从外部获取的字符串插入到查询字符串中.

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <!-- 项目基本信息 --> <groupId>com.example</groupId> <artifactId>art-showcase</artifactId> <version>1.0.0-SNAPSHOT</version> <packaging>jar</packaging> <name>Art Showcase Backend</name> <description>一个基于 Spring Boot 的艺术作品分享平台后端</description> <!-- 使用 Spring Boot 父项目 --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.3.5</version> <!-- 推荐使用稳定版本 --> <relativePath/> </parent> <!-- Java 版本 --> <properties> <java.version>17</java.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <maven.compiler.source>${java.version}</maven.compiler.source> <maven.compiler.target>${java.version}</maven.compiler.target> </properties> <!-- 依赖声明 --> <dependencies> <!-- Spring Boot Web 模块(含 Tomcat + MVC) --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- Spring Data JPA(持久层) --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <!-- MySQL 数据库驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <!-- Spring Security(安全认证) --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <!-- JWT 支持(用于登录 Token) --> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-api</artifactId> <version>0.11.5</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-impl</artifactId> <version>0.11.5</version> <scope>runtime</scope> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-jackson</artifactId> <version>0.11.5</version> <scope>runtime</scope> </dependency> <!-- Lombok(简化 POJO 写法) --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <!-- 测试依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-test</artifactId> <scope>test</scope> </dependency> <!-- 可选:H2 数据库(用于本地测试) --> <!-- <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> --> <!-- 可选:文件上传支持(如图片) --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> </dependencies> <!-- 构建插件 --> <build> <plugins> <!-- Spring Boot 打包插件 --> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> <!-- 编译插件(确保 Java 版本正确) --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.11.0</version> <configuration> <source>${java.version}</source> <target>${java.version}</target> </configuration> </plugin> </plugins> </build> </project>
最新发布
12-25
你提供的 `pom.xml` 文件整体结构良好,使用了 Spring Boot 3.3.5(支持 Jakarta EE),Java 17,并包含了 Web、JPA、Security 等常用模块。 --- ### ✅ **好消息:你的项目其实已经包含验证支持!** 你添加了这个依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> ``` ✅ 这个 starter 已经包含了: - `jakarta.validation-api` - `hibernate-validator` 所以理论上你应该 **可以正常使用** `@NotBlank`, `@Email` 等注解。 --- ### ❌ 那为什么还会报错:“程序包 jakarta.validation.constraints 不存在”? 虽然依赖已声明,但可能由于以下原因导致编译失败: --- ## 🔍 常见原因与解决方案 ### ✅ 1. **Maven 未下载依赖或缓存问题** 即使你在 `pom.xml` 中写了依赖,如果 Maven 没有实际下载它,就会报错。 #### ✔️ 解决方法: 在项目根目录执行以下命令: ```bash # 清理并重新下载依赖 mvn clean compile # 或强制更新快照和依赖 mvn clean compile -U ``` > `-U` 参数会强制 Maven 刷新快照依赖(适合本地缓存损坏时) --- ### ✅ 2. **IDE 未正确识别依赖(尤其是 IntelliJ IDEA)** 有时候 Maven 下载好了,但 IDE 的索引没更新。 #### ✔️ 解决方法(IntelliJ IDEA): 1. 打开 Maven 面板(通常在右侧) 2. 点击 **刷新按钮(Reimport All Maven Projects)** 3. 或菜单:`File → Reload All from Disk` 4. 再尝试编译 --- ### ✅ 3. **检查依赖是否真的存在** 运行以下命令查看是否加载了 validation 相关库: ```bash mvn dependency:tree | grep validation ``` 你应该看到类似输出: ``` [INFO] +- org.springframework.boot:spring-boot-starter-validation:jar:3.3.5:compile [INFO] | +- jakarta.validation:jakarta.validation-api:jar:3.0.2:compile [INFO] | \- org.hibernate.validator:hibernate-validator:jar:8.0.1.Final:compile ``` 如果没有这些内容,请继续下一步。 --- ### ✅ 4. **确认 `spring-boot-starter-validation` 是否拼写正确** 你的写法是正确的 ✅: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> ``` 但如果该依赖被注释掉或拼错(如 `starter-validations` 多了个 s),就会失效。 > ⚠️ 注意:它是可选的(你用了),但必须取消注释才能生效! --- ### ✅ 5. **完整修复流程总结** | 步骤 | 操作 | |------|------| | 1 | 确保 `<dependency>spring-boot-starter-validation</dependency>` **没有被注释** | | 2 | 执行 `mvn clean compile -U` 强制更新依赖 | | 3 | 在 IDE 中刷新 Maven 项目(IntelliJ 点刷新图标) | | 4 | 查看 External Libraries 是否有 `jakarta.validation-api` | | 5 | 尝试重新编译 `RegisterRequest.java` | --- ### ✅ 示例代码验证通过 ✅ 当你修复后,下面这段代码就能正常工作: ```java // RegisterRequest.java package com.example.artshowcase.dto; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.Email; import jakarta.validation.constraints.Size; public class RegisterRequest { @NotBlank(message = "用户名不能为空") @Size(min = 3, max = 20) private String username; @NotBlank @Email(message = "邮箱格式不正确") private String email; @NotBlank @Size(min = 6, max = 20) private String password; // getter / setter... } ``` 并在 Controller 中使用校验: ```java @PostMapping("/register") public ResponseEntity<?> register(@Valid @RequestBody RegisterRequest request) { // 自动校验,失败时抛 MethodArgumentNotValidException userService.register(request); return ResponseEntity.ok("注册成功"); } ``` --- ### 🧪 可选:统一处理校验异常 为了返回友好错误信息,建议添加全局异常处理器: ```java @RestControllerAdvice public class ValidationExceptionHandler { @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity<Map<String, String>> handleValidationExceptions( MethodArgumentNotValidException ex) { Map<String, String> errors = new HashMap<>(); ex.getBindingResult().getAllErrors().forEach((error) -> { String field = ((FieldError) error).getField(); String message = error.getDefaultMessage(); errors.put(field, message); }); return ResponseEntity.badRequest().body(errors); } } ``` --- ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值