ODAC, кажется, кеширует схему таблицы?

Я использую ODAC.NET от Oracle для проекта.NET 3.5 с базой данных Oracle 11 Express, и я вижу поведение, которое не могу объяснить (и, похоже, не могу обойти).

ODAC должен быть последним, я только что вытащил его 3 дня назад, но версии следующие:

  • Oracle.DataAccess.dll версия 2.112.3.0 (выпуск 5)
  • oci.dll (мгновенный клиент) версия 11.2.0.1

У меня есть таблица, Люди, которая имеет 3 столбца:

  • Я БЫ
  • Имя
  • Фамилия

В коде я запускаю команду ALTER TABLE, используя OracleCommand.ExecuteNonQuery, чтобы добавить новый столбец с именем "MIDDLE_NAME" в таблицу. Эта команда успешна. Если я посмотрю на таблицу с Oracle SQL Developer, столбцы отображаются. Все хорошо.

Теперь, если я бегу использовать OracleCommand.ExecuteReader с текстом команды SELECT * FROM People сразу после того, как я выполню таблицу изменений, я получаю данные только с 3 столбцами, а не 4!

Вот код, который воспроизводит проблему:

public void FieldTest()
{
    var sql1 = "CREATE TABLE People (" +
        "ID NUMBER PRIMARY KEY, " +
        "FirstName NVARCHAR2 (200), " +
        "LastName NVARCHAR2 (200) NOT NULL)";

    var sql2 = "ALTER TABLE People " +
        "ADD Middle_Name NUMBER";

    var sql3 = "SELECT * FROM People";

    var sql4 = "SELECT column_name FROM all_tab_cols WHERE table_name = 'PEOPLE'";

    var cnInfo = new OracleConnectionInfo("192.168.10.246", 1521, "XE", "system", "password");
    var connectionString = BuildConnectionString(cnInfo);

    using (var connection = new OracleConnection(connectionString))
    {
        connection.Open();

        using (var create = new OracleCommand(sql1, connection))
        {
            create.ExecuteNonQuery();
        }

        using (var get = new OracleCommand(sql3, connection))
        {
            using (var reader = get.ExecuteReader())
            {
                Debug.WriteLine("Columns: " + reader.FieldCount);
                // outputs 3, which is right
            }
        }

        using (var alter = new OracleCommand(sql2, connection))
        {
            alter.ExecuteNonQuery();
        }

        using (var get = new OracleCommand(sql3, connection))
        {
            using (var reader = get.ExecuteReader())
            {
                Debug.WriteLine("Columns: " + reader.FieldCount);
                // outputs 3, which is *wrong* <---- Here's the problem
            }
        }

        using (var cols = new OracleCommand(sql4, connection))
        {
            using (var reader = cols.ExecuteReader())
            {
                int count = 0;

                while (reader.Read())
                {
                    count++;
                    Debug.WriteLine("Col: " + reader.GetString(0));
                }
                Debug.WriteLine("Columns: " + count.ToString());
                // outputs 4, which is right
            }
        }
    }
}

Я пробовал некоторые вещи, чтобы предотвратить поведение, и ни одна из них не возвращает мне 4-ую колонку:

  • Я закрываю соединение и снова открываю его
  • Я использую новый OracleConnection для SELECT чем для ALTER
  • Я использую то же самое OracleConnection для SELECT и для ALTER
  • Я использую новый OracleCommand для SELECT чем для ALTER
  • Я использую то же самое OracleCommand для SELECT и для ALTER
  • Я звоню PurgeStatementCache на связи между ALTER а также SELECT
  • Я звоню FlushCache на связи между ALTER а также SELECT
  • Я явно Close а также Dispose OracleCommand а также OracleConnection (в отличие от использования блока) используется для ALTER а также SELECT
  • Перезапустил вызывающий ПК и ПК, на котором размещена база данных Oracle.

Если я посмотрю на список столбцов, выполнив SELECT * FROM all_tab_colsновый столбец есть.

Единственная вещь, которая, кажется, работает надежно - это закрытие приложения и его повторный запуск (ну, это из модульного теста, но это завершение работы и перезапуск тестового хоста). Тогда я получаю этот 4-й столбец. Иногда я могу использовать точки останова и повторно выполнять запросы, и появляется 4-й столбец, но ничего, что было бы специально повторяемым при прямом выполнении кода (то есть без установки точки останова и перемещения точки выполнения обратно вверх).

Кажется, что-то в недрах ODAC кеширует схему этой таблицы, но я могу понять, что, почему или как это предотвратить. У кого-нибудь есть опыт или идеи, как я могу это предотвратить?

2 ответа

Я знаю, что этот ответ приходит спустя годы, но если у новых читателей возникнут проблемы с кэшированием, попробуйте установить:

Пул метаданных = ложь, самонастройка = ложь и размер кэша операторов = 0

... в строке подключения. Имейте в виду, что это влияет на производительность.

https://docs.oracle.com/database/122/ODPNT/featConnecting.htm

Может быть, опубликовать некоторые из вашего кода C#. Ниже приведен тест, который ведет себя так, как ожидалось. Это означает, что я могу видеть новый столбец сразу после его добавления. Это использует odp 11.2 rel 5, достигнув 11g db, используя 4.0 framework:

Тестовая таблица:

CREATE TABLE T1
(
  DTE  DATE default sysdate
);

Удалите и воссоздайте его после каждого запуска следующего кода C# (немного грязно, но в любом случае):

string connStr = "User Id=xxx;Password=yyy;Data Source=my11gDb;";
using (OracleConnection con = new OracleConnection(connStr))
{
    string s = "ALTER TABLE T1 ADD (added_col VARCHAR2(10))";
    using (OracleCommand cmd = new OracleCommand(s, con))
    {
        con.Open();
        cmd.ExecuteNonQuery();

        string s2 = "select column_name from all_tab_columns where table_name = 'T1'";
        //con.FlushCache(); // doesn't seem to matter, works with or without

        using (OracleCommand cmd2 = new OracleCommand(s2, con))
        {
            OracleDataReader rdr = cmd2.ExecuteReader();

            for (int i = 0; rdr.Read(); i++)
            {
                Console.WriteLine("Column {0} => {1}",i+1,rdr.GetString(0));
            }
            rdr.Close();
        }
    }
}

Выход:

Column 1 => DTE
Column 2 => ADDED_COL

Редактировать: Ах, хорошо, я понимаю, что вы говорите, это похоже на кеширование операторов. Я поиграл с изменением размера кэша до 0 (в строке conn используйте "Statement Cache Size=0"), а также попробовал cmd.AddToStatementCache = false, но это не сработало.

Одна вещь, которая действительно работает, - это использование немного другой строки, например, добавление пробела. Я знаю, что это хак, но это все, что я могу заставить меня работать.

Попробуйте свой пример с:

var sql3 = "SELECT * FROM People";
var sql5 = "SELECT * FROM People "; // note extra space

И используйте sql3 перед добавлением столбца, и sql5 после добавления столбца.

надеюсь, это поможет

Другие вопросы по тегам