简体   繁体   中英

Include parent and child in query?

I have two entities with one to many relationship like this:

Customer 1......* Booking

 public class Customer
    {
        [Key]
        public int Id { get; set; }
        public string Name { get; set; }
        public List<Booking> Bookings { get; set; }
    }


  public class Booking
    {
        [Key]
        public int Id { get; set; }
        public string Title{ get; set; }
        public DateTime BookingDate { get; set; }
        public int? CustomerId { get; set; }
        public Customer Customer { get; set; };

    }

If _context being DbContext, following two queries ended up in circular dependency.

_context.Customers.Include(x=> x.Bookings).ToList();

OR

_context.Bookings.Include(x=> x.Customer).ToList();

Question is how can we query these interdependent relationships if we have to include entity A in B's query and vice versa?

You can use ForeignKey attribute defined in System.ComponentModel.DataAnnotations.Schema namespace.

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using Microsoft.EntityFrameworkCore;

namespace ParentChild
{
    public class Customer
    {
        [Key]
        public int? Id { get; set; }
        public string Name { get; set; }
        public virtual List<Booking> Bookings { get; set; }
    }

    public class Booking
    {
        [Key]
        public int? Id { get; set; }
        public string Title { get; set; }
        public DateTime? BookingDate { get; set; }
        public int? CustomerId { get; set; }
        [ForeignKey("CustomerId")]
        public virtual Customer Customer { get; set; }
    }

    public class ParentChildDbContext : Microsoft.EntityFrameworkCore.DbContext
    {
        public ParentChildDbContext(String connectionString)
        {
            ConnectionString = connectionString;
        }

        public String ConnectionString { get; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer(ConnectionString);

            base.OnConfiguring(optionsBuilder);
        }

        public DbSet<Customer> Customer { get; set; }

        public DbSet<Booking> Booking { get; set; }
    }

    public class Program
    {
        public static void Main(string[] args)
        {
            var dbContext = new ParentChildDbContext("server=(local);database=ParentChild;integrated security=yes;");

            var data = dbContext.Customer.Include(p => p.Bookings).ToList();

            Console.WriteLine("Customer: {0}, Bookings: {1}", data.First().Name, data.First().Bookings.Count);

            Console.ReadKey();
        }
    }
}

Also, I've created a database for this test:

create database ParentChild
go

use ParentChild
go

create table Customer
(
    Id int not null identity(1, 1),
    Name varchar(50) not null
)

create table Booking
(
    Id int not null identity(1, 1),
    Title varchar(50) not null,
    BookingDate datetime not null,
    CustomerId int not null
)
go

insert into Customer values ('Parent')
go

insert into Booking values ('First booking', getdate(), 1)
go

Output result:

Customer: Parent, Bookings: 1

One possible solution to above problem in my case as I was using Asp.Net Core was to tell in MVC options to handle reference loops as follows:

 services.AddMvc()
                .AddJsonOptions(options =>
                {
                    options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
                });

I have raised an issue with EF core team to answer if reference looping should be handled on consumer end or it should be handled by EF Core. Will update the answer once get a response.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM