web-dev-qa-db-ja.com

LINQを使用したデータの取得

夕方からこの問題に悩まされています。アプリケーションにSQLiteデータベースがあります。そのSQLite DBをファイルから作成しました。 ERDダイアグラムを以下に示します。 enter image description here

そして今、私のアプリケーションでデータベースへの接続を作成します:

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

私は自分のDBのテーブルを表すクラスを作成しました:

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テーブルには、2つの外部キーid_kantoryid_walutyがあります。

そして今、非常に奇妙で奇妙なことが起こりますINNER JOINステートメントで通常のSQLステートメットを使用して情報を取得しようとすると、正常に機能します。

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

このコードは正常に動作します! [〜#〜] but [〜#〜] LINQを使用して次のようにクラスを使用しようとすると:

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

NotSupportedExceptionがスローされます!メッセージは次のとおりですメンバーアクセスが式のコンパイルに失敗しました

しかし、LINQ WITHOUT JOININGを使用してクラスを使用すると、別のクラスが機能します。

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 Applicationなので、Entity Frameworkを使用できません。

11
XardasLord

これが機能するコードです。 SQLite固有のアセンブリなしでEntityFramework 6.3.1のみを使用します。

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固有の参照を参照していますか?

11
Shaun Luttin