源代码
概要:1,明如何使用Entity Framework中的function import功能。
2,说明如何使用ODP.NET的隐式REF CURSOR绑定(implicit REF CURSOR binding)。
环境以及工具:
Windows 10 企业版
Microsoft Visual Studio Enterprise 2015
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0
.NET Framework 4.0
ODP.NET(Nuget Package Id: Oracle.ManagedDataAccess; Nuget Package Version: 12.1.2400)
Entity Framework(Nuget Package Id: EntityFramework; Nuget Package Version: 5.0.0)
其他要求:Oracle数据库中的HR schema访问权限。
1,创建一个Winform项目名称为FunctionImportTest,.NET版本是4.0。
2, 打开Nuget Package Manager控制台。
依次执行如下两个命令分别安装EF和ODP.NET的包:
install-package -id EntityFramework -version 5.0.0 -projectname FunctionImportTest
install-package -id Oracle.ManagedDataAccess -projectname FunctionImportTest
3,在Oracle数据库中的HR方案里面创建一个存储过程。
此存储过程有一个类型为隐式游标变量的出参。
1 CREATE OR REPLACE PROCEDURE "HR"."PROC_GET_EMP_BY_DEPT_NAME" 2 ( 3 DEPT_NAME IN VARCHAR2 DEFAULT NULL, 4 CUR_EMPS OUT SYS_REFCURSOR 5 ) AS 6 SQL_STMT VARCHAR2(256) := 'SELECT t1.first_name, t1.last_name, t2.department_name FROM employees t1 ' || 7 'JOIN departments t2 ON t1.department_id = t2.department_id '; 8 BEGIN 9 IF DEPT_NAME IS NOT NULL THEN 10 SQL_STMT := SQL_STMT || 'WHERE t2.department_name = ' || '''' || DEPT_NAME || ''''; 11 END IF; 12 13 OPEN CUR_EMPS FOR SQL_STMT; 14 END "PROC_GET_EMP_BY_DEPT_NAME";
4,从数据库生成概念模型
(1),在项目名称上点击右键,选择Add-->Add Item。选择ADO.NET Entity Data Model,并把Name设置为HRModel,然后点击Add。
(2),选择从数据库生成模型,点击NEXT。
(3),选择数据库连接。本文使用Oracle数据库中的HR方案。
(4),选择Entity Framework版本。
(5),选择数据库对象及设置。选择上文已经创建的HR.PROC_GET_EMP_BY_DEPT_NAME存储过程,并点击FINISH。
5,此时已经导入了Oracle中的存储过程。然后把存储过程的出参CUR_EMPS映射为具体的类。
导入之后的样子如下图所示:
6,配置app.config文件,设置存储过程的隐式游标参数的元数据信息。
以下是app.config文件中oracle.manageddataaccess.client部分的配置。在设置属性值时,VS基本都有提示。
在implicitRefCursor元素中配置隐式游标变量的绑定信息和元数据。
1 <oracle.manageddataaccess.client> 2 <version number="*"> 3 <dataSources> 4 <dataSource alias="SampleDataSource" descriptor="(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=localhost)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=ORCL))) " /> 5 </dataSources> 6 <implicitRefCursor> 7 <!-- 8 注意:方案名称和存储过程的名称是大小写敏感的。 9 如果要保留方案名称和存储过程名称中的小写字母,则添加"。 10 例如<storedProcedure schema=""SchemaName"" name=""StoredProcedureName""> 11 否则,EF框架会默认把这些名称转换为大写形式。 12 --> 13 <storedProcedure schema="HR" name="PROC_GET_EMP_BY_DEPT_NAME"> 14 <!-- 游标参数的名称是大小写敏感的。 --> 15 <refCursor name="CUR_EMPS"> 16 <bindInfo mode="Output"/> 17 <!-- 参数的序数从0开始 --> 18 <metadata columnName="FIRST_NAME" columnOrdinal="0" columnSize="20" nativeDataType="Varchar2" providerType="Varchar2" providerDBType="String" dataType="System.String" /> 19 <metadata columnName="LAST_NAME" columnOrdinal="1" columnSize="25" nativeDataType="Varchar2" providerType="Varchar2" providerDBType="String" dataType="System.String" /> 20 <metadata columnName="DEPARTMENT_NAME" columnOrdinal="2" columnSize="30" nativeDataType="Varchar2" providerType="Varchar2" providerDBType="String" dataType="System.String" /> 21 </refCursor> 22 </storedProcedure> 23 </implicitRefCursor> 24 </version> 25 </oracle.manageddataaccess.client>
7,把函数导入映射为类型。
(1),修改function import。切换到Model Browser窗口。在Function Imports下面刚才导入的存储过程名称上点击右键,然后点击Edit。
(2),修改function import,并生成Complext Type。
① 修改Function Import Name。
② 选择Returns a Collection Of下面的Complex。
③ 点击Get Column Information。
④ 点击Create New Complex Type。
⑤ 把Complex Type的名称修改为EmployeeBasicInfo。
⑥ 点击OK。
此时,Complex Types下面多了一个类型。
8,剩下的部分就是简单的Winform开发了。调用GetEmpByDeptName方法获取数据,然后和DataGridView控件绑定,把数据显示出来。
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Data; 5 using System.Drawing; 6 using System.Linq; 7 using System.Text; 8 using System.Windows.Forms; 9 10 namespace FunctionImportTest 11 { 12 public partial class FunctionImportForm : Form 13 { 14 // 先创建DbContext 15 private HREntities context = new HREntities(); 16 17 public FunctionImportForm() 18 { 19 InitializeComponent(); 20 } 21 22 private void OnLoad(object sender, EventArgs e) 23 { 24 try 25 { 26 this.Query(null); 27 } 28 catch (Exception ex) 29 { 30 MessageBox.Show(ex.Message); 31 } 32 } 33 34 private void OnClickQueryButton(object sender, EventArgs e) 35 { 36 try 37 { 38 string deptName = this.textBoxDeptNameCondition.Text; 39 this.Query("".Equals(deptName) ? null : deptName); 40 } 41 catch (Exception ex) 42 { 43 MessageBox.Show(ex.Message); 44 } 45 } 46 47 private void Query(string deptName) 48 { 49 this.dataGridViewEmpBasicInfo.DataSource = context.GetEmpByDeptName(deptName); 50 } 51 } 52 }