관련 데이터 로딩

Eunho Bae·2022년 6월 30일
0

DataModel

  [Table("Item")]
    public class Item
    {
        public int ItemId { get; set; }
        public int TemplateId { get; set; }
        public DateTime CreateDate { get; set; }

        [ForeignKey("OwnerId")]
        public Player Owner { get; set; } 
    }

    [Table("Player")]
    public class Player
    {
        public int PlayerId { get; set; } 
        public string Name { get; set; }

        public Item Item { get; set; }
        public Guild Guild { get; set; }
    }

    [Table("Guild")]
    public class Guild
    {
        public int GuildId { get; set; }
        public string GuildName { get; set; }   
        public ICollection<Player> Members { get; set; }   
    }

DbCommands

 public static void CreateTestData(AppDbContext db)
        {
            var strevelun = new Player() { Name = "Strevelun" };
            var rookiss = new Player() { Name = "Rookiss" };
            var faker = new Player() { Name = "faker" };

            List<Item> items = new List<Item>()
            {
                new Item()
                {
                    TemplateId = 101,
                    CreateDate = DateTime.Now,
                    Owner = strevelun,
                },
                new Item()
                {
                    TemplateId = 102,
                    CreateDate = DateTime.Now,
                    Owner = rookiss,
                },
                new Item()
                {
                    TemplateId = 103,
                    CreateDate = DateTime.Now,
                    Owner = faker,
                }
            };

            Guild guild = new Guild()
            {
                GuildName = "T1",
                Members = new List<Player>() { strevelun, rookiss, faker }
            };

            db.Items.AddRange(items);
            db.Guilds.Add(guild);
            db.SaveChanges();
        }

        // 상황 : 특정 길드에 있는 길드원들이 소지한 모든 아이템들을 보고 싶을때
        // 장점 : DB 접근 한 번으로 다 로딩 (JOIN)
        // 단점 : 다 필요하지 않은 경우 
        public static void EagerLoading()
        {
            Console.Write("길드 이름 : ");
            string name = Console.ReadLine();

            using (var db = new AppDbContext())
            {
                // 외부 참조 프로퍼티인 Item은 로딩할때 기본적으로 null로 되어 있기 때문에 우리가 명시적으로 로딩을 해줘야한다. 
                // 이때 명시적으로 로딩시켜주는 함수가 Include이고,
                // 첫번째 Include를 호출할때는 Guild 클래스의 Members만 로딩이 될 것이다.
                // 그러면 Members의 Player 클래스의 Item는 여전히 로딩이 되지 않으며 
                // 여기서는 ThenInclude를 사용해야 한다.
                Guild guild = db.Guilds.AsNoTracking()
                    .Where(g => g.GuildName == name)
                    .Include(g => g.Members)
                    .ThenInclude(p => p.Item)
                    .First(); // 첫번재 하나만 찾기

                foreach(Player player in guild.Members)
                {
                    Console.WriteLine($"ItemId({player.Item.TemplateId}) Owner({player.Name})");
                }
            }
        }

        // AsNoTracking() 호출 금지
        // 장점 : 필요한 시점에 필요한 데이터만 로딩 가능
        // 단점 : DB 접근 비용 높음
        public static void ExplicitLoading()
        {
            Console.Write("길드 이름 : ");
            string name = Console.ReadLine();

            using (var db = new AppDbContext())
            {
                Guild guild = db.Guilds
                    .Where(g => g.GuildName == name)
                    .First();

                // 명시적으로 하나씩 추출
                db.Entry(guild).Collection(g => g.Members).Load(); // guild의 members를 로드

                foreach(Player player in guild.Members)
                {
                    db.Entry(player).Reference(p => p.Item).Load(); // Item은 하나만 존재. p.Item을 찾아달라
                }

                foreach (Player player in guild.Members)
                {
                    Console.WriteLine($"ItemId({player.Item.TemplateId}) Owner({player.Name})");
                }
            }
        }

        // 상황 : 특정 길드에 있는 길드원 수를 알고 싶을때
        // 장점 : 필요한 정보만 빼서 로딩
        // 단점 : 일일히 Select 안에 Name, MemberCount같은 것을 만들어줘야 한다.
        public static void SelectLoading()
        {
            Console.Write("길드 이름 : ");
            string name = Console.ReadLine();

            using (var db = new AppDbContext())
            {
                var info = db.Guilds
                   .Where(g => g.GuildName == name)
                   .Select(g => new
                   {
                       Name = g.GuildName,
                       MemberCount = g.Members.Count
                   })
                   .First();

                Console.WriteLine($"GuildName({info.Name}), MemberCount({info.MemberCount}");
            }
        }
profile
개인 공부 정리

0개의 댓글