Получение данных с помощью LINQ

Я застрял с этой проблемой с нескольких вечеров. У меня есть база данных SQLite в моем приложении. Я создал эту БД SQLite из файла. Диаграмма ERD показана ниже: enter image description here

И теперь в моем приложении я создаю соединение с моей базой данных:

using (var conn = new SQLiteConnection(DB_PATH))
{
    // retrieving statemets...
}

Я создал классы, которые представляют таблицы в моей БД:

public class Kantory
{
        public Kantory()
        {
            this.kursy = new HashSet<Kursy>();
        }

        [SQLite.PrimaryKey, SQLite.AutoIncrement]
        public int id_kantory { get; set; }
        public string nazwa { get; set; }

        public virtual ICollection<Kursy> kursy { get; set; }
}

public class Waluty
{
        public Waluty()
        {
            this.kursy = new HashSet<Kursy>();
        }

        [SQLite.PrimaryKey, SQLite.AutoIncrement]
        public int id_waluty { get; set; }
        public string nazwa { get; set; }

        public virtual ICollection<Kursy> kursy { get; set; }
}

public class Kursy
{
        [SQLite.PrimaryKey, SQLite.AutoIncrement]
        public int id_kursy { get; set; }
        public int id_kantory { get; set; }
        public int id_waluty { get; set; }
        public decimal kurs { get; set; }
        public System.DateTime data { get; set; }
        public int aktualne { get; set; }

        public virtual Kantory kantory { get; set; }
        public virtual Waluty waluty { get; set; }
}

Как вы можете видеть, в таблице kursy у меня есть два внешних ключа - id_kantory и id_waluty.

И теперь происходит очень любопытная и странная вещь. Когда я пытаюсь получить некоторую информацию, используя обычные SQL-выражения с помощью оператора INNER JOIN, он работает нормально:

using (var conn = new SQLiteConnection(DB_PATH))
{
    var query = new SQLiteCommand(conn);
    query.CommandText = "SELECT * FROM Kursy INNER JOIN Kantory ON Kursy.id_kursy=Kantory.id_kantory WHERE Kantory.id_kantory = 1";
    var result = query.ExecuteQuery<Kursy>();
}

Этот код работает отлично! НО, когда я пытаюсь использовать свои классы с помощью LINQ, например:

using (var conn = new SQLiteConnection(DB_PATH))
{
    var result = conn.Table<Kursy>().Where(k => k.kantory.id_kantory == 1).FirstOrDefault();
}

Это выдает мне NotSupportedException! Сообщение выглядит так: При доступе к члену не удалось скомпилировать выражение

НО, когда я использую свои классы, используя LINQ БЕЗ СОЕДИНЕНИЯ другого класса, это работает:

using (var conn = new SQLiteConnection(DB_PATH))
{
        var result = conn.Table<Kursy>().Where(k => k.id_kursy == 1).FirstOrDefault();
}

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

PS. Это приложение для Windows Phone 8.1, поэтому я не могу использовать Entity Framework для этого.

Ответ 1

Вот код, который работает. Он использует только EntityFramework 6.3.1 без каких-либо специфических для SQLite сборок.

Я понимаю, что вы НЕ хотите использовать Entity Framework. Чтобы добавить ответ для этого, подумайте, нам нужно знать, что SQLite конкретные сборки, которые вы используете. Например, используете ли вы DbLinq?

В частности, какие сборки содержат следующие методы?

  • SQLiteCommand.ExecuteQuery<T>()
  • SQLiteConnection.Table<T>()

В любом случае, вот код, который работает с Entity Framework.

using System;
using System.Linq;
using System.Data.Entity;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

namespace SQLite
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var conn = new SQLiteConnection(@"C:\linqToSqlite.db"))
            {
                SeedEntities(conn);

                // this is the query that DID work for you
                var result1 = conn.Kursy
                    .Where(k => k.id_kursy == 1)
                    .FirstOrDefault();

                Console.WriteLine(
                    string.Format("id_kursy:{0}", result1.id_kursy));

                // this is the query that did NOT work for you
                // it does work here
                var result2 = conn.Kursy
                    .Where(k => k.kantory.id_kantory == 1)
                    .FirstOrDefault();

                Console.WriteLine(
                    string.Format("id_kursy:{0}", result2.id_kantory));
            }

            Console.ReadKey();
        }

        private static void SeedEntities(SQLiteConnection conn)
        {
            SeedEntities(conn);
            // make sure two entities exist with the appropriate ids
            if (!conn.Kantory.Any(x => x.id_kantory == 1))
            {
                conn.Kantory
                    .Add(new Kantory() { id_kantory = 1 });
            }

            if (!conn.Kursy.Any(x => x.id_kantory == 1))
            {
                conn.Kursy
                    .Add(new Kursy() { id_kantory = 1 });
            }

            conn.SaveChanges();
        }        
    }

    public class SQLiteConnection : DbContext
    {
        public SQLiteConnection(string connString) : 
            base(connString) {}
        public DbSet<Kantory> Kantory { get; set; }
        public DbSet<Kursy> Kursy { get; set; }
    }

    public class Kantory
    {
        public Kantory()
        {
            this.kursy = new HashSet<Kursy>();
        }

        [Key]
        public int id_kantory { get; set; }
        public virtual ICollection<Kursy> kursy { get; set; }
    }

    public class Kursy
    {
        [Key]
        public int id_kursy { get; set; }
        public int id_kantory { get; set; }
        public virtual Kantory kantory { get; set; }
    }
}

Боюсь, я использовал другую технику, чем вы, потому что я не знал точных сборок, которые вы использовали. Например, неясно, какую сборку вы использовали для метода Table<T>(). Итак, я использовал подход DbContext.Kursy и следующие ссылки:

  • EntityFramework.dll
  • EntityFramework.SqlServer.dll
  • System.dll
  • System.ComponentModel.DataAnnotations.dll

Другими словами, он работает просто с EntityFramework 6.1.3 и не требует каких-либо SQLite конкретных сборок.

Для ответа, соответствующего вашим потребностям, какие SQLite конкретные ссылки вы ссылаетесь?