Oracle
 sql >> Teknologi Basis Data >  >> RDS >> Oracle

Berurusan dengan data JSON besar yang dikembalikan oleh Web API

Masalah Anda adalah Anda menjalankan kueri Oracle yang mengembalikan sejumlah besar hasil, dan kemudian memuat seluruh hasil yang ditetapkan ke dalam memori sebelum membuat serial ke HttpResponseMessage .

Untuk mengurangi penggunaan memori, Anda harus menemukan dan menghilangkan semua kasus di mana seluruh rangkaian hasil dari kueri dimuat ke dalam representasi perantara sementara (mis. DataTable atau string JSON), dan alih-alih mengalirkan data menggunakan DataReader . Ini menghindari menarik semuanya ke dalam memori sekaligus menurut jawaban ini .

Pertama, dari traceback Anda, tampaknya Anda memiliki Aktifkan Tautan Peramban diperiksa. Karena ini tampaknya mencoba untuk men-cache seluruh respons dalam MemoryStream , Anda akan ingin menonaktifkannya seperti yang dijelaskan dalam FilePathResult melempar OutOfMemoryException dengan file besar .

Selanjutnya, Anda dapat melakukan streaming konten IDataReader langsung ke JSON menggunakan Json.NET dengan kelas dan konverter berikut:

[JsonConverter(typeof(OracleDataTableJsonResponseConverter))]
public sealed class OracleDataTableJsonResponse
{
    public string ConnectionString { get; private set; }
    public string QueryString { get; private set; }
    public OracleParameter[] Parameters { get; private set; }

    public OracleDataTableJsonResponse(string connStr, string strQuery, OracleParameter[] prms)
    {
        this.ConnectionString = connStr;
        this.QueryString = strQuery;
        this.Parameters = prms;
    }
}

class OracleDataTableJsonResponseConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(OracleDataTableJsonResponse);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException("OracleDataTableJsonResponse is only for writing JSON.  To read, deserialize into a DataTable");
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var response = (OracleDataTableJsonResponse)value;

        using (var dbconn = new OracleConnection(response.ConnectionString))
        {
            dbconn.Open();
            using (var selectCommand = new OracleCommand(response.QueryString, dbconn))
            {
                if (response.Parameters != null)
                    selectCommand.Parameters.AddRange(response.Parameters);
                using (var reader = selectCommand.ExecuteReader())
                {
                    writer.WriteDataTable(reader, serializer);
                }
            }
        }
    }
}

public static class JsonExtensions
{
    public static void WriteDataTable(this JsonWriter writer, IDataReader reader, JsonSerializer serializer)
    {
        if (writer == null || reader == null || serializer == null)
            throw new ArgumentNullException();
        writer.WriteStartArray();
        while (reader.Read())
        {
            writer.WriteStartObject();
            for (int i = 0; i < reader.FieldCount; i++)
            {
                writer.WritePropertyName(reader.GetName(i));
                serializer.Serialize(writer, reader[i]);
            }
            writer.WriteEndObject();
        }
        writer.WriteEndArray();
    }
}

Kemudian ubah kode Anda agar terlihat seperti:

    public HttpResponseMessage Getdetails([FromUri] string[] id)
    {
        var prms = new List<OracleParameter>();
        var connStr = ConfigurationManager.ConnectionStrings["PDataConnection"].ConnectionString;
        var inconditions = id.Distinct().ToArray();
        var strQuery = @"SELECT 
                       STCD_PRIO_CATEGORY_DESCR.DESCR AS CATEGORY, 
                       STCD_PRIO_CATEGORY_DESCR.SESSION_NUM AS SESSION_NUMBER, 
                       Trunc(STCD_PRIO_CATEGORY_DESCR.START_DATE) AS SESSION_START_DATE, 
                       STCD_PRIO_CATEGORY_DESCR.START_DATE AS SESSION_START_TIME , 
                       Trunc(STCD_PRIO_CATEGORY_DESCR.END_DATE) AS SESSION_END_DATE, 
                         FROM 
                         STCD_PRIO_CATEGORY_DESCR, 
                         WHERE 
                        STCD_PRIO_CATEGORY_DESCR.STD_REF IN(";
        var sb = new StringBuilder(strQuery);
        for (int x = 0; x < inconditions.Length; x++)
        {
            sb.Append(":p" + x + ",");
            var p = new OracleParameter(":p" + x, OracleDbType.NVarchar2);
            p.Value = inconditions[x];
            prms.Add(p);
        }
        if (sb.Length > 0)// Should this be inconditions.Length > 0  ?
            sb.Length--;
        strQuery = sb.Append(")").ToString();

        var returnObject = new { data = new OracleDataTableJsonResponse(connStr, strQuery, prms.ToArray()) };
        var response = Request.CreateResponse(HttpStatusCode.OK, returnObject, MediaTypeHeaderValue.Parse("application/json"));
        ContentDispositionHeaderValue contentDisposition = null;
        if (ContentDispositionHeaderValue.TryParse("inline; filename=ProvantisStudyData.json", out contentDisposition))
        {
            response.Content.Headers.ContentDisposition = contentDisposition;
        }
        return response;
    }

Ini menghindari DataSet . dalam memori representasi hasil.

Kebetulan, saya rasa garisnya

        if (sb.Length > 0)
            sb.Length--;

sebaliknya seharusnya:

        if (inconditions.Length > 0)
            sb.Length--;

Saya yakin Anda mencoba menghilangkan tanda koma dalam kueri, yang akan muncul jika dan hanya jika inconditions.Length > 0

Harap dicatat - saya bukan pengembang Oracle dan saya tidak menginstal Oracle. Untuk pengujian saya mengejek OracleClient kelas menggunakan OleDbConnection yang mendasarinya dan berhasil dengan baik.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Cara terbaik untuk melakukan penyisipan multi-baris di Oracle?

  2. Jalankan Prosedur Tersimpan SQL Server melalui Tautan Database dari Oracle

  3. 2 Cara Mendapatkan Jumlah Hari dalam Sebulan di Oracle

  4. Oracle sql - pengurangan tanggal dalam suatu fungsi

  5. Apakah mungkin menggunakan pengembalian dalam prosedur tersimpan?