Oracle存储过程与.net的ORM风格映射



我正在寻找某种工具来帮助从。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

最新更新