Entity Framework & Oracle, Linq, где сравнения строк предложений не возвращают никаких записей, если дан параметр функции, а не литерал - PullRequest
2 голосов
/ 12 июля 2019

Я пишу приложение на C # в .Net Core v.2.2.300, которое использует Entity Framework и Devart.Data.Oracle для извлечения исходного кода из нашей базы данных Oracle с использованием таблицы SYS.DBA_SOURCE в базе данных, в которой хранится каждая строка. кода базы данных в виде отдельной записи. Цель состоит в том, чтобы мы провели некоторый автоматический анализ. Для этого я создал функцию GetSourceCode, которой передаются имя схемы, имя объекта и тип объекта (PACKAGE / FUNCTION и т. Д.). Эта функция использует Linq и фильтрует dba_source (OWNER, NAME, TYPE, LINE, TEXT) только для записей, в которых данный владелец, имя и тип соответствуют тем, которые указаны в параметрах функции. Тем не менее, этот запрос всегда ничего не возвращает при использовании параметров, даже если я проверил непосредственно с базой данных, что записи существуют и должны были быть получены. Если я жестко закодирую строковые значения в запросе, тогда он работает, но это сводит на нет цель использования функции. Пользователь базы данных, которым я пользуюсь, может подключиться к базе данных и имеет разрешение на просмотр рассматриваемой таблицы, поэтому это не проблема разрешения, но я считаю, что это как-то связано с преобразованием Linq в SQL.

Жесткое кодирование строковых значений в сравнение предложения where работает для извлечения данных, но не со значениями, передаваемыми в качестве параметров, если только мы не копируем параметры (используя конструктор копирования строки) внутри предложения (копирование ничего не делает вне предложения where).

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

Я полагаю, что именно это копирование строки при каждой проверке предложения where вызывает медленную работу программы.

В основном я хотел бы знать, почему я вижу поведение, которое я вижу, а также то, как я могу изменить запрос linq, чтобы использовать аргументы функции, не создавая этого огромного замедления.

Следующий исходный код не работает и всегда возвращает пустую строку, хотя я могу использовать эквивалентный sql непосредственно в моей базе данных с теми же параметрами и получить правильные результаты (исходный код указанного файла)

private string GetSourceCode(string name, string owner, string oracleType) {
var qry = DbaSource
                .Where((row) => (
                    row.Name.Equals(name) &&
                    row.Type.Equals(oracleType) &&
                    row.Owner.Equals(owner)
                )).OrderBy((row) => row.Line)
                .Select((row) => row.Text)
                .ToList()
                .Aggregate(new StringBuilder(), (sb, line) => sb.AppendLine(line), sb => sb.ToString());

return qry;
}

Однако я могу жестко запрограммировать значения и получить правильные результаты для этих входных данных

var qry = DbaSource
                .Where((row) => (
                    row.Name.Equals("Example Table Name") &&
                    row.Type.Equals("PACKAGE") &&
                    row.Owner.Equals("Example Schema Name")
                )).OrderBy((row) => row.Line)
                .Select((row) => row.Text)
                .ToList()
                .Aggregate(new StringBuilder(), (sb, line) => sb.AppendLine(line), sb => sb.ToString());

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

var qry = DbaSource
                .Where((row) => (
                    row.Name.Equals(new string(name)) &&
                    row.Type.Equals(new string(oracleType)) &&
                    row.Owner.Equals(new string(owner))
                )).OrderBy((row) => row.Line)
                .Select((row) => row.Text)
                .ToList()
                .Aggregate(new StringBuilder(), (sb, line) => sb.AppendLine(line), sb => sb.ToString());

Где объект DbaSource описывается

public DbSet<Models.Sys.DbaSource> DbaSource {get; set;}

namespace Models.Sys {

[Table("DBA_SOURCE", Schema="SYS")]
    public class DbaSource{
        [Column("OWNER", Order = 0)]
        public string Owner {get; set;}

        [Column("NAME", Order = 1)]
        public string Name {get; set;}

        [Column("TYPE", Order = 2)]
        public string Type {get; set;}

        [Column("LINE", Order = 3)]
        public decimal Line {get; set;}

        [Column("TEXT")]
        public string Text {get; set;}

        [Column("ORIGIN_CON_ID")]
        public decimal OriginConId {get; set;}

        public static Expression<Func<DbaSource, object>> GetPrimaryKey() {
            return r => new { r.Owner, r.Name, r.Type, r.Line };
        }

        public override string ToString() {
            return string.Format("{0}|{1}|{2}|{3}|{4}|{5}", Owner, Name, Type, Line, Text, OriginConId);
        }
    }

}

Я надеюсь, что этой информации достаточно, чтобы описать проблему, которую я вижу, так как это поведение совершенно неожиданно, трудно описать и совсем не логично для меня, но, учитывая мой ограниченный опыт работы с Entity Framework, я считаю, что что-то происходит с Linq to SQL, это проблема.

Я ожидаю получить исходный код для данного объекта базы данных в виде одной строки в течение нескольких секунд, используя функцию, которая позволяет мне передавать различные значения для различных объектов в течение разумного периода времени.

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

1 Ответ

0 голосов
/ 12 июля 2019

Проблема в том, что EF QueryProvider не будет правильно конвертировать row.Name.Equals(name).Вы должны использовать row.Name == name вместо этого.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...