7

编辑:根据测试更新问题描述 - 2011 年 9 月 12 日。

我有这个查询,每当我调用 .ToList() 时都会引发 NotSupportedException(“不支持指定的方法。”)。

IQueryable<FileDefinition> query = db
    .FileDefinitions
    .Include(x => x.DefinitionChangeLogs)
    .Include(x => x.FieldDefinitions.Select(y => y.DefinitionChangeLogs)) // bad
    .Include(x => x.FieldDefinitions.Select(y => y.FieldValidationTables)) // bad
    .Where(x => x.IsActive);
List<FileDefinition> retval = query.ToList();

如果我注释掉我注释为“坏”的任何一行,则查询有效。我还尝试在我的对象模型中包含不同的嵌套实体,效果相同。包括任何 2 都会导致崩溃。嵌套是指导航属性的导航属性。我还尝试使用带有字符串路径的 .Include 方法:结果相同。

我的表结构如下所示:

数据库模型

数据库模型 2

这是使用 MySQL 5.1(显然是 InnoDB 表)作为 MySQL Connector/NET 6.3.4 的数据库存储。

所以我的问题是:为什么这不起作用?

注意:如果我像在这个链接中那样显式加载相关实体,我可以让它工作。但我想知道为什么 EF 讨厌我的数据模型。

解答: MySQL 连接器显然无法处理第二个嵌套实体包含。它抛出 NotSupportedException,而不是 .NET EF。当我使用 EF4.0 尝试此操作时,也出现了同样的错误,但我当时的研究让我相信这是导致问题的自我跟踪实体。我尝试升级到最新的连接器,但它开始导致Out of Sync 错误。这也是我讨厌 MySQL 的另一个原因

4

2 回答 2

3

聚会可能有点晚了,但我发现以下解决方法在当前项目中相当有用:

IQueryable<FileDefinition> query = db.FileDefinitions
    .Include(x => x.FieldDefinitions.Select(y => y.DefinitionChangeLogs.Select(z => z.FieldDefinition.FieldValidationTables)))

与其使用第二行包含,不如使用 Select 返回原始导航属性,使用另一个 Select 前进到您需要包含的属性。

于 2014-04-14T11:56:17.813 回答
2

我制作了一个小控制台应用程序来测试您的场景,这个测试应用程序可以工作:

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

namespace EFIncludeTest
{
    public class Parent
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public ICollection<ChildLevel1> ChildLevel1s { get; set; }
    }

    public class ChildLevel1
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public ICollection<ChildLevel2a> ChildLevel2as { get; set; }
        public ICollection<ChildLevel2b> ChildLevel2bs { get; set; }
    }

    public class ChildLevel2a
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

    public class ChildLevel2b
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

    public class MyContext : DbContext
    {
        public DbSet<Parent> Parents { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            // Create entities to test
            using (var ctx = new MyContext())
            {
                var parent = new Parent
                {
                    Name = "Parent",
                    ChildLevel1s = new List<ChildLevel1>
                    {
                        new ChildLevel1
                        {
                            Name = "FirstChildLevel1",
                            ChildLevel2as = new List<ChildLevel2a>
                            {
                                new ChildLevel2a { Name = "FirstChildLevel2a" },
                                new ChildLevel2a { Name = "SecondChildLevel2a" }
                            },
                            ChildLevel2bs = new List<ChildLevel2b>
                            {
                                new ChildLevel2b { Name = "FirstChildLevel2b" },
                                new ChildLevel2b { Name = "SecondChildLevel2b" }
                            }
                        },

                        new ChildLevel1
                        {
                            Name = "SecondChildLevel1",
                            ChildLevel2as = new List<ChildLevel2a>
                            {
                                new ChildLevel2a { Name = "ThirdChildLevel2a" },
                                new ChildLevel2a { Name = "ForthChildLevel2a" }
                            },
                            ChildLevel2bs = new List<ChildLevel2b>
                            {
                                new ChildLevel2b { Name = "ThirdChildLevel2b" },
                                new ChildLevel2b { Name = "ForthChildLevel2b" }
                            }
                        },
                    }
                };

                ctx.Parents.Add(parent);
                ctx.SaveChanges();
            }

            // Retrieve in new context
            using (var ctx = new MyContext())
            {
                var parents = ctx.Parents
                    .Include(p => p.ChildLevel1s.Select(c => c.ChildLevel2as))
                    .Include(p => p.ChildLevel1s.Select(c => c.ChildLevel2bs))
                    .Where(p => p.Name == "Parent")
                    .ToList();

                // No exception occurs
                // Check in debugger: all children are loaded

                Console.ReadLine();
            }
        }
    }
}

我的理解是,这基本上代表了您的模型和您正在尝试的查询(还要考虑您对问题的评论)。但是某处必须是一个重要的区别,这在您的问题的代码片段中不可见,并且使您的模型无法工作。

编辑

我已经使用 MS SQL 提供程序(SQL Server 2008 R2 Express DB)测试了上面的工作控制台应用程序,而不是 MySQL 连接器。显然这是“重要的区别”。

于 2011-09-12T20:59:37.950 回答