将Oracle关联数组移植到Postgres并使用npgsql包装数据访问

时间:2017-12-25 17:58:07

标签: postgresql npgsql dotconnect

很高兴得到对npgsql查询的快速回复。感谢它的主人!我试图将带有数组值参数的sproc移植到具有类似抽象/语义的postgres。我想知道如何塑造pgsql sproc并使用npgsql api来调用它。我在dal抽象之上有另一层应用程序抽象。我们使用数据适配器转到sql server,将数组关联到oracle并试图找出我们可以使用npgsql将其映射到postgres的内容。我们在塑造sproc方面有一些空间,但仍然保持输入参数的数量相同。我们当然可以建立这个sproc很不一样但我们仍然需要它在相同的app api后面,它提供了一些类型化的数组,如下所示

public static void Flush2OraWithAssocArrayInsnetworkdatabatch(string dbKey  ,int?[] ENDPOINTID,DateTime?[] INSERTEDDATETIME,int?[] RECORDTYPEID,long?[] RECORDVALUE,int?[] PACKETSIZE)
    { 
         Database db = Helper.GetDatabase(dbKey);
          using (DbConnection con = db.CreateConnection()){
                con.Open();
                using (DbCommand cmd  = con.CreateCommand()){
                    cmd.CommandText =  "Insnetworkdatabatch";
                    Helper.InitializeCommand(cmd, 300, "Insnetworkdatabatch");
                    BuildInsnetworkdatabatchOracleAssocArrayCommandParameters(cmd ,ENDPOINTID,INSERTEDDATETIME,RECORDTYPEID,RECORDVALUE,PACKETSIZE);
                    try {
                        Helper.ExecuteNonQuery(cmd, cmd.CommandText);
                        con.Close();
                    } catch (DALException ) {
                        throw;
                    } 
             }
        }
    }

我有一个oracle sproc,如下所示

create or replace PROCEDURE InsNetworkDataBatch2
  (
    -- Add the parameters for the stored procedure here
    v_endPointID       IN arrays.t_number ,
    v_insertedDateTime IN arrays.t_date ,
    v_recordTypeID     IN arrays.t_number ,
    v_recordValue      IN arrays.t_number ,
    v_packetSize       IN arrays.t_number )
AS
BEGIN
  DECLARE 
  BEGIN
    FORALL i IN v_endpointID.FIRST..v_endpointID.LAST SAVE EXCEPTIONS
      INSERT
      INTO STGNETWORKSTATS
        (
          INSERTEDDATE,
          ENDPOINTID,
          RECORDTYPEID,
          RECORDVALUE,
          PACKETSIZE
        )
        VALUES
        (
          v_insertedDateTime(i),
          v_endPointID(i),
          v_recordTypeID(i),
          v_recordValue(i),
          v_packetSize(i)
        );

  END;
END;
-- END PL/SQL BLOCK (do not remove this line) ----------------------------------

这是oracle中的assoc数组包

  create or replace PACKAGE Arrays AS

 type t_number is table of number index by binary_integer;
 type t_date is table of date index by binary_integer; 
END Arrays; 

以下是我们如何构建oracle parm并想知道它在postgres中是否具有等价性并试图了解npgsql将如何支持它

   public override void CreateAssociativeArrayParameter(DbCommand cmd, string parameterName, object parameterValue, string dbType, ParameterDirection direction)
    {
        OracleDbType oracleDbType = dbSpecificTypesMap[dbType];
        OracleParameter param = new OracleParameter(parameterName, oracleDbType, direction);
        param.CollectionType = OracleCollectionType.PLSQLAssociativeArray;
        param.Value = parameterValue;
        cmd.Parameters.Add(param);
    }

2 个答案:

答案 0 :(得分:0)

我对Oracle数组或关联数组一无所知。但是,PostgreSQL对复杂类型有着丰富的支持。 PostgreSQL arrays是在列中存储值数组的好方法,PostgreSQL甚至提供索引和数据库端函数来处理数组。

如果您正在寻找字典类型(关联数组?),请查看hstorejson

已编辑:如果您的关联区域具有固定架构(即字段不会更改),您还可以考虑PostgreSQL composite

答案 1 :(得分:0)

这是使用Postgres存储过程的尝试。这现在正在运作。我解决了从npgsql内部抛出的一些转换问题,这是因为我的.net类型与postgres中的sproc参数数据类型不兼容。

Here is how i am trying to add the param value

create or replace FUNCTION InsNetworkDataBatch
  (
    -- Add the parameters for the stored procedure here
    v_endPointID       IN int[] ,
    v_insertedDateTime IN timestamp[] ,
    v_recordTypeID     IN int[] ,
    v_recordValue      IN bigint[] ,
    v_packetSize       IN int[] ) RETURNS void
      LANGUAGE 'plpgsql'

AS $$
BEGIN
  DECLARE 
  BEGIN

 FOR i IN array_lower(v_endPointID, 1) .. array_upper(v_endPointID, 1)
    loop 
     INSERT INTO STGNETWORKSTATS
        (
          INSERTEDDATE,
          ENDPOINTID,
          RECORDTYPEID,
          RECORDVALUE,
          PACKETSIZE
        )
        VALUES
        (
          v_insertedDateTime[i],
          v_endPointID[i],
          v_recordTypeID[i],
          v_recordValue[i],
          v_packetSize[i]
        ); 
   end loop; 

  END; 
END;
$$

以下是我尝试将应用程序绑定到命令参数

的方法
public override void CreateAssociativeArrayParameter(DbCommand cmd, string parameterName, object parameterValue, string dbType, ParameterDirection direction)
        {
            NpgsqlDbType npgsqlDbType;
            if (dbSpecificTypesMap.ContainsKey(dbType))
            {
                npgsqlDbType = dbSpecificTypesMap[dbType];
            }
            else
            {
                throw new ApplicationException($"The db type {dbType} could not be parsed into the target NpgsqlDbType. Please check the underlying type of the parameter");
            }
            NpgsqlParameter param = new NpgsqlParameter(parameterName.ToLower(),  NpgsqlDbType.Array | npgsqlDbType); 
            param.Value = parameterValue;
            cmd.Parameters.Add(param);
        }