我正在寻找某种工具来帮助从。net代码调用Oracle存储过程。我们有一个大型的遗留数据库,坦率地说有点混乱(没有id字段、大型组合键和重复数据)。目前,我们必须通过一个旧的、有bug的自定义库来做所有的数据访问。
我对像nHibernate这样的ORM工具有一些经验,但是在我们的环境中试用了一下之后,它似乎并不是处理像这样的遗留数据库的最佳选择。
有没有人知道一个很好的工具,可以让存储过程被轻松调用,并将结果映射到对象的集合/集合?一个不错的好处是能够处理连接事务。
谢谢
新的Oracle beta实体框架驱动程序允许您这样做。您可以将SP映射到模型中,或者映射到实体(如果它们返回的是一个表),或者创建一个"复杂类型",这是一个围绕SP返回的内容构建的类。
我不知道你打电话给了多少人,但我试过的那些人都成功了。
另一个选择是编写自己的库,它只调用过程并以。net类的形式返回结果,但这将需要大量的重复代码设置工作(在Oracle中将参数映射到过程是非常繁琐的)。
edit -这是一个配置文件条目,用于使用存储过程,其中结果来自作为OUT参数的游标。
<oracle.dataaccess.client>
<settings>
<add name="ENVMSTR.P_ORG_UNIT_R_BY_STAFF.RefCursor.RESULT_CURSOR_P" value="implicitRefCursor bindinfo='mode=Output'" />
</settings>
</oracle.dataaccess.client>
编辑2 -和问题的存储过程:
create or replace
PROCEDURE P_ORG_UNIT_R_BY_STAFF
(
STAFF_ID_P IN NUMBER
, RESULT_CURSOR_P OUT SYS_REFCURSOR
) AS
BEGIN
OPEN RESULT_CURSOR_P FOR
select *
from dept_organizational_unit
start with deptorgunit_cd = (select deptorgunit_cd from staff where staff_id = STAFF_ID_P)
connect by prior deptorgunit_parent_cd = deptorgunit_cd;
END P_ORG_UNIT_R_BY_STAFF;
如果一个商业库是一个选择,我们真的很高兴与Devart(见http://www.devart.com/dotconnect/oracle/features.html)…他们支持LINQ, PLINQ, EF,存储过程,REF游标等-从Oracle 7.3到11g/. net 2及以上/32 + 64位…
不隶属,只是一个快乐的客户…
如果你只想要SPROC处理参数化和物化(数据到对象),dapper-dot-net是简单的,极简的,应该在Oracle上工作得很好;例如:
var user = cnn.Query<User>("spGetUser", new {Id = 1},
commandType: CommandType.StoredProcedure).First();
点:
-
spGetUser
是进程的名称 - 通过
commandType
作为进程调用 - 参数是从传入的对象推导出来的;在这种情况下,假设有一个名为
Id
的参数,它接受一个整数,1
的值在 中传递。 - 应用直接的列到属性映射,为返回的每一行构造一个
User
对象 - 在本例中,我们也使用LINQ-to-Objects来演示读取一行
注意,还支持映射多个数据网格和水平分区(到相关图中的不同对象)。
对于那些试图获得实体框架函数导入与Oracle工作的人,这里有一个演练,你可以使用:http://www.oracle.com/webfolder/technetwork/tutorials/obe/db/dotnet/EntityFrameworkOBE/EntityFrameworkOBE.htm
我还写了一篇杂志文章,其中包括一篇攻略:http://www.oracle.com/technetwork/issue - archive/2011/11 sep/o51odt - 453447. - html
注意:在发布这篇文章的时候,由于在beta3中发生的app.config关键字的一些变化,这些演练不工作。请参阅ODP中的自述文件。. NET目录下的beta3.
已更改的影响演练的关键字可按如下方式修改:
NATIVE_DATA_TYPE到NATIVEDATATYPE
和
PROVIDER_DB_TYPE to PROVIDERDBTYPE
请参阅ODT目录中的自述文件,了解与此相关的其他注意事项。在(未来的)生产版本中(在本文发布时不可用),Oracle Developer Tools for Visual Studio在线帮助有一个名为"使用实体框架"的部分。本节包含到存储过程和函数映射的注意事项。请阅读本文档
有关此app.config元数据格式的更多信息,请参阅ODP。. NET联机帮助中的"隐式REF CURSOR绑定支持"小节。
注意,这个详细的app.config元数据只有在你使用复杂类型作为映射结果时才需要。如果您返回一个实体,则不需要它。
不幸的是,修改app.config的过程充满了出错的可能性。任何错误都会导致导入功能向导上的"获取列信息"按钮什么都不做。我们意识到了这一点,并计划在未来的版本中提供一个配置工具。
基督教谢甲骨文您最好为您的数据访问层使用代码生成器。写起来很容易。它甚至可以生成CRUD PL/SQL。
这里有一个小例子:
Private Sub GeneraCapaAccesoDato(ByVal tipo As Integer, ByVal modo As String)
Dim sb As New StringBuilder()
Dim Tabla As String = lbTabla.SelectedValue
Dim dt As DataTable = RecuperarDatosTabla(Tabla)
sb.Append(String.Format("public int {1}(OracleConnection con, BE{0} oBE{0})", Tabla, modo))
sb.AppendLine("{")
sb.AppendLine("int Resultado;")
sb.AppendLine(String.Format("OracleCommand cmd = new OracleCommand(""Pa_{0}_{1}"", con);", Tabla, modo))
sb.AppendLine("cmd.CommandType = CommandType.StoredProcedure;")
sb.AppendLine("")
Dim i As Integer
Row = dt.Select()
Dim NomTabla As String
Dim Tamaño As Integer
Dim scala As Integer
Dim TipoDato As String = "Ninguno"
Dim precision As Integer
Dim aux As Object
Dim aux1 As Object
Dim llave As Integer
For i = tipo To Row.Count() - 1
llave = Int32.Parse(Row(i).Item(7))
NomTabla = Row(i).Item(0).ToString()
Tamaño = Integer.Parse(Row(i).Item(2).ToString())
aux = Row(i).Item(4).ToString()
scala = Integer.Parse(If(aux = "", 0, aux))
aux1 = Row(i).Item(3).ToString()
precision = Integer.Parse(If(aux1 = "", 0, aux1))
If scala > 0 Then
If scala >= 0 And scala <= 15 Then
TipoDato = "OracleDbType.Double"
End If
ElseIf Row(i).Item(1).ToString() = "NUMBER" Then
If precision < 2 Then
TipoDato = "OracleDbType.Int16"
ElseIf precision >= 2 And precision <= 9 Then
TipoDato = "OracleDbType.Int32"
ElseIf precision >= 10 And precision <= 18 Then
TipoDato = "OracleDbType.Int64"
End If
Else
If Row(i).Item(1).ToString() = "DATE" Then
TipoDato = "OracleDbType.Date "
End If
If Row(i).Item(1).ToString() = "VARCHAR2" Then
TipoDato = "OracleDbType.Varchar2 "
End If
If Row(i).Item(1).ToString() = "CHAR" Then
TipoDato = "OracleDbType.Char "
End If
End If
sb.AppendLine(String.Format("OracleParameter Par{1} = cmd.Parameters.Add(""P_{0}"",{2});", _
NomTabla, If(tipo = 0, i + 1, i), TipoDato))
If Row(i).Item(1).ToString() = "VARCHAR2" Or Row(i).Item(1).ToString() = "CHAR" Then
sb.AppendLine(String.Format("Par{1}.Size = {0};", Tamaño, If(tipo = 0, i + 1, i)))
End If
sb.AppendLine(String.Format("Par{0}.Direction = ParameterDirection.Input;", If(tipo = 0, i + 1, i)))
sb.AppendLine(String.Format("Par{0}.Value = oBE{2}.{1};", If(tipo = 0, i + 1, i), NomTabla, Tabla))
sb.AppendLine("")
TipoDato = ""
Next
sb.AppendLine("Resultado = cmd.ExecuteNonQuery();")
sb.AppendLine("return Resultado;")
sb.AppendLine("}")
rtbVisor.Text = sb.ToString()
End Sub
Private Function RecuperarDatosTabla(ByVal NombreTabla As String) As DataTable
sb = New StringBuilder
sb.Append(" select COLUMN_NAME, DATA_TYPE, DATA_LENGTH, DATA_PRECISION, DATA_SCALE, NULLABLE, DATA_DEFAULT ,column_id")
sb.Append(" from(USER_TAB_COLUMNS)")
sb.Append(String.Format(" where TABLE_NAME = '{0}' order by table_name,column_id ", NombreTabla))
Using con As New OracleConnection(strConexion)
con.Open()
dt = New DataTable
Dim da As OracleDataAdapter = New OracleDataAdapter(sb.ToString(), con)
da.Fill(dt)
End Using
Return dt
End Function