Entity Framework执行带COMMIT的INSERT ALL时遇ORA-00933错误
Entity Framework迁移执行Oracle SQL文件遇ORA-00933错误的解决办法
问题重现
使用Entity Framework迁移时,通过SqlResource读取SQL文件执行数据导入,代码如下:
迁移代码:
public override void Up() { this.SqlResource("Migrations.SqlMigrations.ImportData.sql"); }
执行命令:
Update-Database -SourceMigration 0 -StartUpProjectName Test
SQL文件内容(简化版):
INSERT ALL INTO PLZ (PLZ_PK, PLZ, LOCATION, CREATION_DATE, CREATED_BY) VALUES ('1', '111111', 'Testcity1', to_timestamp('15.12.09 09:15:00,000000000'), 'Init Dateimport') INTO PLZ (PLZ_PK, PLZ, LOCATION, CREATION_DATE, CREATED_BY) VALUES ('2', '222222', 'Testcity2', to_timestamp('15.12.09 09:15:00,000000000'), 'Init Dateimport') ... SELECT * FROM dual COMMIT INSERT ALL INTO PLZ (PLZ_PK, PLZ, LOCATION, CREATION_DATE, CREATED_BY) VALUES ('3', '333333', 'Testcity3', to_timestamp('15.12.09 09:15:00,000000000'), 'Init Dateimport') ... SELECT * FROM dual
注:省略号表示中间包含500条数据,该写法在Oracle SQL Developer中可正常运行,但EF执行时抛出ORA-00933: SQL command not properly ended错误。
问题原因
- EF默认将整个SQL文件视为单条命令执行,而Oracle不允许在普通SQL语句中直接使用
COMMIT,必须包裹在PL/SQL块内。 - 多个INSERT ALL块直接拼接时,EF的语句解析逻辑无法正确分割独立命令,导致语法识别错误。
解决方案
方案1:用PL/SQL块包裹SQL内容
修改SQL文件,将所有语句放在BEGIN...END;块中,让Oracle能正确处理COMMIT命令:
BEGIN INSERT ALL INTO PLZ (PLZ_PK, PLZ, LOCATION, CREATION_DATE, CREATED_BY) VALUES ('1', '111111', 'Testcity1', to_timestamp('15.12.09 09:15:00,000000000'), 'Init Dateimport') INTO PLZ (PLZ_PK, PLZ, LOCATION, CREATION_DATE, CREATED_BY) VALUES ('2', '222222', 'Testcity2', to_timestamp('15.12.09 09:15:00,000000000'), 'Init Dateimport') ... SELECT * FROM dual; COMMIT; INSERT ALL INTO PLZ (PLZ_PK, PLZ, LOCATION, CREATION_DATE, CREATED_BY) VALUES ('3', '333333', 'Testcity3', to_timestamp('15.12.09 09:15:00,000000000'), 'Init Dateimport') ... SELECT * FROM dual; COMMIT; END; /
此方式将整个内容作为单条PL/SQL命令执行,既符合Oracle语法要求,也适配EF的命令解析逻辑。
方案2:在EF迁移中拆分执行语句
若不想修改SQL文件,可在Up方法中拆分SQL内容,逐块调用Sql方法执行:
public override void Up() { // 执行第一个INSERT ALL块及COMMIT this.Sql(@"INSERT ALL INTO PLZ (PLZ_PK, PLZ, LOCATION, CREATION_DATE, CREATED_BY) VALUES ('1', '111111', 'Testcity1', to_timestamp('15.12.09 09:15:00,000000000'), 'Init Dateimport') ... SELECT * FROM dual; COMMIT;"); // 执行第二个INSERT ALL块 this.Sql(@"INSERT ALL INTO PLZ (PLZ_PK, PLZ, LOCATION, CREATION_DATE, CREATED_BY) VALUES ('3', '333333', 'Testcity3', to_timestamp('15.12.09 09:15:00,000000000'), 'Init Dateimport') ... SELECT * FROM dual;"); }
此方式需确保每个语句块是独立的合法Oracle命令,适合SQL结构清晰的场景。
额外注意点
- Oracle的INSERT ALL语句必须以
SELECT * FROM dual;结尾,且分号不能省略,否则会触发语法错误。 - 普通SQL语句中禁止直接使用COMMIT,必须放在PL/SQL块内或作为独立命令执行。
内容的提问来源于stack exchange,提问作者optPr1me
相关产品推荐
相关产品推荐

