LINQ несколько объединений с различными объектами - PullRequest
0 голосов
/ 24 августа 2018

Я работал над программой на C #, которая использует LINQ для управления простой базой данных SQLite.База данных состоит из разных таблиц, которые в моем коде представлены разными классами.Вот как я создаю таблицы:

    public ITable<Doctors> Doctors => GetTable<Doctors>();

    public ITable<Patients> Patients=> GetTable<Patients>();

    public ITable<Prescriptions> Prescriptions=>GetTable<Prescriptions>();

    public ITable<Assistants> Assistants=> GetTable<Assistants>();

    public ITable<Medicines> Medicines => GetTable<Medicines>();

    public ITable<General_medicines> General_medicines=> GetTable<General_medicines>();

    public ITable<Stocks> Stocks=> GetTable<Stocks>();

    public ITable<Dosages> Dosages=> GetTable<Dosages>();

    public ITable<Recipes> Recipes=> GetTable<Recipes>();

    public ITable<Prescriptions_MP> Prescriptions_MP=> GetTable<Prescriptions_MP>();

Теперь я хочу создать запрос LINQ (в отдельном классе), в котором я получаю разные свойства во всех этих таблицах и помещаю их в IEnumerable, который яможет позже сканировать.Для этого я действую следующим образом:

public IEnumerable<Therapy> TakePrescriptions()
{
            HealthDataContext DbContext = DbFactory.Create();
            var dbPrescriptions = DbContext.GetTable<Prescriptions>();
            IEnumerable<Prescriptions> prescriptions= dbPrescriptions.AsEnumerable();

            var dbPatients= DbContext.GetTable<Patients>();
            IEnumerable<Pazienti> patients= dbPatients.AsEnumerable();

            var dbPrescrizioniMP = DbContext.GetTable<Prescriptions_MP>();
            IEnumerable<Prescriptions_MP> prescriptionsMP = dbPrescriptionsMP .AsEnumerable();

            var dbRecipes = DbContext.GetTable<Recipes>();
            IEnumerable<Recipes> recipes= dbRecipes .AsEnumerable();

            var dbMedicines= DbContext.GetTable<Medicines>();
            IEnumerable<Medicines> medicines= dbMedicines.AsEnumerable();

            var dbGeneral_medicines = DbContext.GetTable<General_medicines>();
            IEnumerable<General_medicines> general_medicines= dbGeneral_medicines.AsEnumerable();

            var dbDosages = DbContext.GetTable<Dosages>();
            IEnumerable<Dosages> dosages= dbDosages .AsEnumerable();

            var query = from p in patients
                            join pr in prescriptions_MP on p.Id equals pr.Patient
                            join pre in prescriptions on pr.Prescription equals pre.Id
                            join fc in medicines on pre.Medicine equals fc.Id
                            join fg in general_medicines on fc.Medicine equals fg.Id
                            join ds in dosages on fg.Id equals ds.General_Medicine
                            where p.Doctor== IdDoctor
                            select new
                            {
                                IdDoctor, //int
                                p.Name, //string
                                pr.Prescription, //int
                                pre.Id, //int
                                fc.Format, //string 
                                fc.Administration, //string
                                fc.Downloadable, //boolean
                                fc.Full_stomach, //boolean
                                nameM= fg.Name, //string
                                ds.Quantity, //int
                                ds.Hour //string
                            };


            List < Therapy> therapy = new List<Therapy>();



            foreach(var object in query)
            {
                Therapy t = new Therapy(IdDoctor, object.Name, object.Prescription, object.Id, object.Format, object .Administration, object.Downloadable, object.Full_stomach, object.nameM, object.Quantity, object.Hour);

                therapy.Add(t);

            }

            return therapy;
}

Теперь, когда я пытаюсь загрузить страницу, которая должна отображать список результатов, я получаю InvalidOperationException: с этой командой связан открытый читатель,Закройте его перед изменением свойства CommandText. в операции foreach .

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

Я пытался избавиться от DBContext, но затем я получил это исключение: ObjectDisposedException: IDataContext удален, см. https://github.com/linq2db/linq2db/wiki/Managing-data-connectionИмя объекта: «DataConnection».

Ответы [ 2 ]

0 голосов
/ 19 ноября 2018

Вы должны удалить AsEnumerable() вызовы из таблиц, которые вы используете в запросе, потому что они заставляют linq2db выполнять их как отдельные запросы.

Это имеет два последствия:

  • попыткичтобы запустить несколько запросов по одному соединению БД, которое не поддерживается, и вы получите InvalidOperationException
  • , давайте представим, что это будет работать (например, вы заменили AsEnumerable() на ToList(), чтобы прочитать все данные из каждого запроса).В этом случае он загрузит все данные в приложение и выполнит соединения в коде C # - это приведет к очень плохой производительности, особенно в тех случаях, когда вам нужно отбросить некоторые данные, которые не соответствуют условиям соединения.
0 голосов
/ 24 августа 2018

Вы получаете сообщение об ошибке «С этой командой связан открытый читатель.Закройте его перед изменением свойства CommandText », предполагает, что открыто несколько читателей.Однако, глядя на ваш запрос, кажется, что один читатель открыт для вашего одного запроса.Реальность однако отличается.У вас есть 5 таблиц, каждая из которых имеет отношение 1 ко многим к другой таблице.Например, таблица «пациент» имеет отношение «1 ко многим» к таблице рецептов.Как пациент может иметь несколько рецептов.

Таким образом, просто рассматривая эти две таблицы, у нас сначала есть один запрос для загрузки всех пациентов, а затем еще один запрос для каждого пациента для загрузки всех его рецептов, это означает, что если у вас N пациентов, это переводится как 1 +N запрос, 1 для загрузки всех пациентов и N для загрузки рецептов каждого из этих пациентов.

Теперь, учитывая 5-уровневое объединение, которое у вас есть в коде и выполняем математику, вы можете увидеть, сколько существует потенциальных открытых читателей.Данные загружаются по требованию, что означает, что считыватели активируются после итерации по результатам вашего запроса, это позволяет избежать чрезмерного использования памяти, что приводит к снижению производительности и, следовательно, когда в цикле foreach вы начинаете перебирать объекты, данные для реального извлечения.

Чтобы решить эту проблему, вы можете попробовать преобразовать ToList в конце вашего запроса, чтобы поощрить привязку (таким образом, нетерпеливую загрузку), или, как один из комментаторов предлагает передать MultipleActiveResultSets = true в строку подключения.

...