sql >> データベース >  >> RDS >> Mysql

MySQL Connector / NETを使用して、深さ2を超えるオブジェクトグラフでEntity Frameworkを使用するにはどうすればよいですか?

    編集

    以下のテストは、SQLServerとSqlClientを使用して行われました。 プロバイダーとして。問題がSQLServerで再現できないという事実は、MySqlの場合に疑問を投げかけます。 使用しているプロバイダーには、LINQクエリに対して誤ったSQLを作成するというバグがあります。 この質問 と同じ問題のようです MySqlで問題が発生した場所 プロバイダーも同様であり、SqlClientでは再現できませんでした /SQLServer。

    太字の例(EF 4.3.1を使用)をテストしましたが、問題を再現できません:

    using System;
    using System.Collections.Generic;
    using System.Data.Entity;
    using System.Linq;
    
    namespace EFInclude
    {
        public class Harbor
        {
            public int HarborId { get; set; }
            public virtual ICollection<Ship> Ships { get; set; }
    
            public string Description { get; set; }
        }
    
        public class Ship
        {
            public int ShipId { get; set; }
            public int HarborId { get; set; }
            public virtual Harbor Harbor { get; set; }
            public virtual ICollection<CrewMember> CrewMembers { get; set; }
    
            public string Description { get; set; }
        }
    
        public class CrewMember
        {
            public int CrewMemberId { get; set; }
            public int ShipId { get; set; }
            public virtual Ship Ship { get; set; }
            public int RankId { get; set; }
            public virtual Rank Rank { get; set; }
            public int ClearanceId { get; set; }
            public virtual Clearance Clearance { get; set; }
    
            public string Description { get; set; }
        }
    
        public class Rank
        {
            public int RankId { get; set; }
            public virtual ICollection<CrewMember> CrewMembers { get; set; }
    
            public string Description { get; set; }
        }
    
        public class Clearance
        {
            public int ClearanceId { get; set; }
            public virtual ICollection<CrewMember> CrewMembers { get; set; }
    
            public string Description { get; set; }
        }
    
        public class MyContext : DbContext
        {
            public DbSet<Harbor> Harbors { get; set; }
            public DbSet<Ship> Ships { get; set; }
            public DbSet<CrewMember> CrewMembers { get; set; }
            public DbSet<Rank> Ranks { get; set; }
            public DbSet<Clearance> Clearances { get; set; }
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                Database.SetInitializer(new DropCreateDatabaseAlways<MyContext>());
    
                using (var context = new MyContext())
                {
                    context.Database.Initialize(true);
    
                    var harbor = new Harbor
                    {
                        Ships = new HashSet<Ship>
                        {
                            new Ship
                            {
                                CrewMembers = new HashSet<CrewMember>
                                {
                                    new CrewMember
                                    {
                                        Rank = new Rank { Description = "Rank A" },
                                        Clearance = new Clearance { Description = "Clearance A" },
                                        Description = "CrewMember A"
                                    },
                                    new CrewMember
                                    {
                                        Rank = new Rank { Description = "Rank B" },
                                        Clearance = new Clearance { Description = "Clearance B" },
                                        Description = "CrewMember B"
                                    }
                                },
                                Description = "Ship AB"
                            },
                            new Ship
                            {
                                CrewMembers = new HashSet<CrewMember>
                                {
                                    new CrewMember
                                    {
                                        Rank = new Rank { Description = "Rank C" },
                                        Clearance = new Clearance { Description = "Clearance C" },
                                        Description = "CrewMember C"
                                    },
                                    new CrewMember
                                    {
                                        Rank = new Rank { Description = "Rank D" },
                                        Clearance = new Clearance { Description = "Clearance D" },
                                        Description = "CrewMember D"
                                    }
                                },
                                Description = "Ship CD"
                            }
                        },
                        Description = "Harbor ABCD"
                    };
    
                    context.Harbors.Add(harbor);
                    context.SaveChanges();
                }
    
                using (var context = new MyContext())
                {
                    DbSet<Harbor> dbSet = context.Set<Harbor>();
                    IQueryable<Harbor> query = dbSet;
                    query = query.Include(entity => entity.Ships);
                    query = query.Include(entity => entity.Ships.Select(s => s.CrewMembers));
                    query = query.Include(entity => entity.Ships.Select(s => s.CrewMembers.Select(cm => cm.Rank)));
                    query = query.Include(entity => entity.Ships.Select(s => s.CrewMembers.Select(cm => cm.Clearance)));
    
                    var sqlString = query.ToString();
                    // see below for the generated SQL query
    
                    var harbor = query.Single();
    
                    Console.WriteLine("Harbor {0} Description = \"{1}\"",
                        harbor.HarborId, harbor.Description);
                    foreach (var ship in harbor.Ships)
                    {
                        Console.WriteLine("- Ship {0} Description = \"{1}\"",
                            ship.ShipId, ship.Description);
                        foreach (var crewMember in ship.CrewMembers)
                        {
                            Console.WriteLine("-- CrewMember {0} Description = \"{1}\"", 
                                crewMember.CrewMemberId, crewMember.Description);
                            Console.WriteLine("-- CrewMember {0} Rank Description = \"{1}\"",
                                crewMember.CrewMemberId, crewMember.Rank.Description);
                            Console.WriteLine("-- CrewMember {0} Clearance Description = \"{1}\"",
                                crewMember.CrewMemberId, crewMember.Clearance.Description);
                        }
                    }
    
                    Console.ReadLine();
                }
            }
        }
    }
    

    出力は次のとおりです。

    太字の説明によると、次のようになります。 CrewMember 1 Description ="Rank A" 他の3人の乗組員も同じように混乱しました。しかし、私はこれをしていません。

    エラーが発生したコードと比較して、私のテストプログラムには何か違いがありますか?

    編集

    クエリ用に生成されたSQL(var sqlString = query.ToString();の行を参照してください。 上記のソースコードで、以下はsqlStringの内容です。 )は:

    SELECT 
    [Project1].[HarborId] AS [HarborId], 
    [Project1].[Description] AS [Description], 
    [Project1].[C2] AS [C1], 
    [Project1].[ShipId] AS [ShipId], 
    [Project1].[HarborId1] AS [HarborId1], 
    [Project1].[Description1] AS [Description1], 
    [Project1].[C1] AS [C2], 
    [Project1].[CrewMemberId] AS [CrewMemberId], 
    [Project1].[ShipId1] AS [ShipId1], 
    [Project1].[RankId] AS [RankId], 
    [Project1].[ClearanceId] AS [ClearanceId], 
    [Project1].[Description2] AS [Description2], 
    [Project1].[RankId1] AS [RankId1], 
    [Project1].[Description3] AS [Description3], 
    [Project1].[ClearanceId1] AS [ClearanceId1], 
    [Project1].[Description4] AS [Description4]
    FROM ( SELECT 
        [Extent1].[HarborId] AS [HarborId], 
        [Extent1].[Description] AS [Description], 
        [Join3].[ShipId1] AS [ShipId], 
        [Join3].[HarborId] AS [HarborId1], 
        [Join3].[Description1] AS [Description1], 
        [Join3].[CrewMemberId] AS [CrewMemberId], 
        [Join3].[ShipId2] AS [ShipId1], 
        [Join3].[RankId1] AS [RankId], 
        [Join3].[ClearanceId1] AS [ClearanceId], 
        [Join3].[Description2] AS [Description2], 
        [Join3].[RankId2] AS [RankId1], 
        [Join3].[Description3] AS [Description3], 
        [Join3].[ClearanceId2] AS [ClearanceId1], 
        [Join3].[Description4] AS [Description4], 
        CASE WHEN ([Join3].[ShipId1] IS NULL) THEN CAST(NULL AS int) WHEN ([Join3].[CrewMemberId] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1], 
        CASE WHEN ([Join3].[ShipId1] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C2]
        FROM  [dbo].[Harbors] AS [Extent1]
        LEFT OUTER JOIN  (SELECT [Extent2].[ShipId] AS [ShipId1], [Extent2].[HarborId] AS [HarborId], [Extent2].[Description] AS [Description1], [Join2].[CrewMemberId], [Join2].[ShipId2], [Join2].[RankId1], [Join2].[ClearanceId1], [Join2].[Description2], [Join2].[RankId2], [Join2].[Description3], [Join2].[ClearanceId2], [Join2].[Description4]
            FROM  [dbo].[Ships] AS [Extent2]
            LEFT OUTER JOIN  (SELECT [Extent3].[CrewMemberId] AS [CrewMemberId], [Extent3].[ShipId] AS [ShipId2], [Extent3].[RankId] AS [RankId1], [Extent3].[ClearanceId] AS [ClearanceId1], [Extent3].[Description] AS [Description2], [Extent4].[RankId] AS [RankId2], [Extent4].[Description] AS [Description3], [Extent5].[ClearanceId] AS [ClearanceId2], [Extent5].[Description] AS [Description4]
                FROM   [dbo].[CrewMembers] AS [Extent3]
                INNER JOIN [dbo].[Ranks] AS [Extent4] ON [Extent3].[RankId] = [Extent4].[RankId]
                LEFT OUTER JOIN [dbo].[Clearances] AS [Extent5] ON [Extent3].[ClearanceId] = [Extent5].[ClearanceId] ) AS [Join2] ON [Extent2].[ShipId] = [Join2].[ShipId2] ) AS [Join3] ON [Extent1].[HarborId] = [Join3].[HarborId]
    )  AS [Project1]
    ORDER BY [Project1].[HarborId] ASC, [Project1].[C2] ASC, [Project1].[ShipId] ASC, [Project1].[C1] ASC
    


    1. LinuxでデフォルトのMySQL/MariaDBポートを変更する方法

    2. phpmysql_connect警告無効

    3. MySqlでIN句を使用する別のアプローチ

    4. ConcatのGroup_ConcatがNULL値で機能しない