web-dev-qa-db-fra.com

Récupération de données à l'aide de LINQ

Je suis coincé avec ce problème depuis quelques soirées. J'ai SQLite base de données dans mon application. J'ai créé cette base de données SQLite à partir d'un fichier. Le diagramme ERD est illustré ci-dessous: enter image description here

Et maintenant, dans mon application, je crée une connexion à ma base de données:

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

J'ai créé des classes qui représentent des tables dans ma base de données:

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

Comme vous pouvez le voir, dans la table kursy, j'ai deux clés étrangères - id_kantory et id_waluty.

Et maintenant une chose très curieuse et étrange se produit. Lorsque j'essaie de récupérer des informations à l'aide de statemets SQL normaux avec INNER JOIN déclaration - cela fonctionne très bien:

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

Ce code fonctionne bien! MAIS lorsque j'essaie d'utiliser mes classes en utilisant LINQ comme ceci:

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

Cela me lance une exception NotSupportedException! Le message est: L'accès des membres n'a pas réussi à compiler l'expression

MAIS quand j'utilise mes classes en utilisant LINQ WITHOUT JOINING une autre classe cela fonctionne:

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

Donc à la fin: mon principal problème est que je ne peux pas joindre plus d'une table en utilisant une requête LINQ. On dirait que ce modèle en classe est faux mais je ne sais vraiment pas pourquoi ...

PS. Il s'agit de l'application Windows Phone 8.1 , donc je ne peux pas utiliser Entity Framework pour cela.

11
XardasLord

Voici un code qui fonctionne. Il utilise uniquement EntityFramework 6.3.1 sans aucun assemblage spécifique à SQLite.

Je comprends que vous ne voulez PAS utiliser Entity Framework. Pour ajouter une réponse à cela, nous avons besoin de savoir ce que SQLite assemblages spécifiques que vous utilisez. Par exemple, utilisez-vous DbLinq ?

Plus précisément, quels assemblages contiennent les méthodes suivantes?

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

Dans tous les cas, voici du code qui fonctionne avec 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; }
    }
}

J'ai bien peur d'avoir utilisé une technique différente de la vôtre, car je ne connaissais pas les assemblages exacts que vous avez utilisés. Par exemple, il n'était pas clair quel Assembly vous avez utilisé pour la méthode Table<T>(). J'ai donc utilisé l'approche DbContext.Kursy À la place et les références suivantes:

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

En d'autres termes, il fonctionne simplement avec EntityFramework 6.1.3 et ne nécessite aucun assemblage spécifique SQLite.

Pour une réponse adaptée à vos besoins, à quelles SQLite références spécifiques faites-vous référence?

11
Shaun Luttin