【问题标题】:Retrieving data using LINQ使用 LINQ 检索数据
【发布时间】:2015-02-07 13:01:40
【问题描述】:

自从几个晚上以来,我一直被这个问题困扰。我的应用程序中有SQLite 数据库。我已经从一个文件创建了那个 SQLite DB。 ERD 图如下所示:

现在我在我的应用程序中创建了一个到我的数据库的连接:

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_kantoryid_waluty

现在发生了非常奇怪和奇怪的事情。当我尝试使用带有INNER JOIN 语句的普通SQL statemets 检索一些信息时 - 它工作正常:

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 应用程序,所以我不能为此使用实体框架。

【问题讨论】:

  • Sqlite-net 不支持外键
  • @ErikEJ,嗯,但是当我使用如上所示的普通 SQL 语句使用SELECT ... FROM ... INNER JOIN... 时,它可以工作。所以它可能使用外键,不是吗?
  • 它不会将连接从 LINQ 转换为 SQL
  • 在哪里告诉编译器Kursy.id_kantory 是支持导航到虚拟Kursy.kantory 属性的外键?在实体框架中,this can be done in multiple ways,如约定。它在您的代码中是如何工作的?
  • 您在SQLiteCommand 上运行ExecuteQuery&lt;T&gt; 的情况如何?您如何在SQLiteConnection 上运行Table&lt;T&gt;()?那些不能开箱即用。您引用了哪些程序集和命名空间来获得对它们的访问权限?

标签: c# .net linq sqlite join


【解决方案1】:

这是有效的代码。它仅使用 EntityFramework 6.3.1,没有任何 SQLite 特定程序集。

我知道您不想使用实体框架。要为此添加答案,我们需要知道您正在使用什么SQLite 特定程序集。例如,您使用的是DbLinq吗?

具体来说,哪些程序集包含以下方法?

  • SQLiteCommand.ExecuteQuery&lt;T&gt;()
  • SQLiteConnection.Table&lt;T&gt;()

无论如何,这里是适用于实体框架的代码。

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&lt;T&gt;() 方法中使用了哪个程序集。所以,我改用DbContext.Kursy 方法和以下参考:

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

换句话说,它只适用于 EntityFramework 6.1.3,不需要任何 SQLite 特定程序集。

对于与您的需求相关的答案,您引用了哪些SQLite 特定参考?

【讨论】:

  • 谢谢你!在我的情况下,我没有将我的 FK 属性设置为虚拟,并且 LINQ 没有填充它们。例如public string Colour_Id { get; set; } [ForeignKey("Colour_Id")] public virtual Colour Colour { get; set; }
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多