Oracle
 sql >> база данни >  >> RDS >> Oracle

Работа с големи JSON данни, върнати от Web API

Проблемът ви е, че изпълнявате заявка на Oracle, която връща много голям брой резултати и след това зареждате целия набор от резултати в паметта, преди да го сериализирате в HttpResponseMessage .

За да намалите използването на паметта си, трябва да намерите и елиминирате всички случаи, при които целият набор от резултати от заявката се зарежда във временно междинно представяне (напр. DataTable или JSON низ) и вместо това предавайте поточно данните с помощта на DataReader . Това избягва изтеглянето на всичко в паметта наведнъж според този отговор .

Първо, от вашето проследяване изглежда, че имате Активиране на връзка към браузъра проверено. Тъй като това очевидно се опитва да кешира целия отговор в MemoryStream , ще искате да го деактивирате, както е обяснено в FilePathResult хвърли OutOfMemoryException с голям файл .

След това можете да предавате поточно съдържанието на IDataReader директно към JSON с помощта на Json.NET със следния клас и конвертор:

[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();
    }
}

След това променете кода си така, че да изглежда така:

    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;
    }

Това избягва DataSet в паметта представяне на резултатите.

Между другото, смятам линията

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

вместо това трябва да бъде:

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

Вярвам, че се опитвате да отлепите запетаята в края на заявката, която ще присъства, ако и само ако inconditions.Length > 0

Моля, обърнете внимание - аз не съм разработчик на Oracle и нямам инсталиран Oracle. За тестване макирах OracleClient класове, използващи основен OleDbConnection и работи добре.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Свързване към Oracle:CodeIgniter срещу Laravel

  2. Принудително намаляване на глобалната таблица на Oracle

  3. Извличане на последно вмъкнатата IDENTITY на Oracle

  4. Заменете REGEXP_SUBSTR в SQL Server

  5. Архивиране на база данни на Oracle:Тип архивиране и стратегия за архивиране