In my application, users can make requests for more information. I then need to be able to pull this information , but I also need to be able to see which bookings the user who made the request has already made.
I have set the following up with EF Core:
Models:
public class InfoRequest
{
public int InfoRequestId { get; set; }
public int UserId { get; set; }
public User User { get; set }
}
public class User
{
public int UserId { get; set; }
public ICollection<Booking> { get; set; }
}
public class Booking
{
public int BookingId { get; set; }
public int UserId { get; set; }
public User User { get; set }
}
Context:
modelBuilder.Entity<InfoRequest>(builder =>
{
builder.ToTable("inforequests");
builder.HasKey(x => x.InfoRequestId);
});
modelBuilder.Entity<User>(builder =>
{
builder.ToTable("userdetails");
builder.HasKey(x => x.UserId);
builder
.HasMany(x => x.Bookings)
.WithOne(x => x.User)
.HasForeignKey(x => x.UserId);
});
modelBuilder.Entity<Booking>(builder =>
{
builder.ToTable("bookings");
builder.HasKey(x => x.BookingId);
});
I am using the following code to pull the data I need:
public IQueryable<InfoRequest> GetAllInfoRequestsWithChildren()
=> this.Context.Set<InfoRequest>().AsNoTracking()
.Include(x => x.User)
.ThenInclude(x => x.Bookings);
Annoyingly, this is giving my the following self-referencing data structure which is obviously super slow:
InfoRequest
-> User
-> Booking
-> User
-> Booking
-> User
-> Booking
-> etc...
How can I prevent this from happening without pulling it all into memory with a ToList()
and then removing the loop manually? I just want EF to not create a loop in the first place.
What I want is the following:
InfoRequest
-> User
-> Booking
You cannot stop proxy creation while using Eager Loading in EF/EF Core. This is the default behavior of EF/EF core and no way to change this.
But may be (I didn't try out) you can stop the proxy creation for Lazy Loading in EF Core >=2.1 as EF Core documentation said.
But you can stop Self referencing loop
due to the proxies while you converting the entity to JSON
as follows:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddMvc()
.AddJsonOptions(
options => options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
);
...
}
For more details: Related data and serialization