0

I have four blog records in my Sqlite database and two author records. When I try and get the blogs, I'm having EF core get the related data (in this case, the Author) and set the Author object in my Blog object.

public async Task<List<Blog>> GetAllBlogs(BlogContext context) 
{
    return context.Blogs.Include(a => a.Author).ToList();
}

This works well and good, but it seems I'm only ever being returned unique instances of the author throughout the dataset. Here is the json result of GetAllBlogs:

    {
  "$id": "1",
  "result": {
    "$id": "2",
    "$values": [
      {
        "$id": "3",
        "blogId": "77da9a11-f752-4260-bebd-c1dbf7031d13",
        "author": {
          "$id": "4",
          "authorId": "ced0627d-bb4f-4941-a718-dd2438f0bf51",
          "authorFirstName": "John",
          "authorMiddleName": "R",
          "authorLastName": "Smith",
          "briefDescription": "Cool guy",
          "createdDate": "2023-01-10T22:22:51.7759933",
          "modifiedDate": null,
          "archivedDate": null
        },
        "blogTitle": "string",
        "blogContent": "string",
        "blogTags": "string",
        "createdDate": "2023-04-05T20:27:50.4621096",
        "modifiedDate": null,
        "archivedDate": null
      },
      {
        "$id": "5",
        "blogId": "96b0ae6d-d924-4099-87dd-5a8c7be50eed",
        "author": {
          "$id": "6",
          "authorId": "1d9ee13a-2581-44a4-94d6-b201506c4d29",
          "authorFirstName": "T",
          "authorMiddleName": "R",
          "authorLastName": "B",
          "briefDescription": "T B is a fullstack software developer with an emphesis on .NET and JavaScript technologies.",
          "createdDate": "2023-01-10T22:22:51.7759933",
          "modifiedDate": null,
          "archivedDate": null
        },
        "blogTitle": "asdfasdf",
        "blogContent": "asdfasfasfasdf",
        "blogTags": "",
        "createdDate": "2023-04-05T20:30:20.1779955",
        "modifiedDate": null,
        "archivedDate": null
      },
      {
        "$id": "7",
        "blogId": "494ea31d-40ea-4722-af56-3c2fb7aa260f",
        "author": {
          "$ref": "6"
        },
        "blogTitle": "asdf",
        "blogContent": "asf",
        "blogTags": "",
        "createdDate": "2023-04-05T20:38:14.3230626",
        "modifiedDate": null,
        "archivedDate": null
      },
      {
        "$id": "8",
        "blogId": "005ab54d-3bca-4d9d-8532-ca5613e8b5b7",
        "author": {
          "$ref": "6"
        },
        "blogTitle": "Title",
        "blogContent": "*content!",
        "blogTags": "",
        "createdDate": "2023-04-05T20:38:47.3545631",
        "modifiedDate": null,
        "archivedDate": null
      }
    ]
  }
}

My two authors do show up under the appropriate blog records, but they're only ever showing up once even though they're present under other records.

Below is my database context class:

using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using backend.Models;

public class BlogContext : DbContext 
{

//protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
//=> optionsBuilder
//  .UseLazyLoadingProxies()
//  .UseSqlite("Data source=web.db");
    

public BlogContext(DbContextOptions<BlogContext> options) : base(options)
{
    
}
public DbSet<Blog> Blogs {get; set;}
public DbSet<Author> Authors {get; set;}

}

My blog class:

using System.ComponentModel.DataAnnotations;

namespace backend.Models
{
    public class Blog : Times
    {
    [Key]
    public String BlogId {get; set;}
    public virtual Author Author { get; set; }
    public String BlogTitle {get; set;}
    public String BlogContent {get; set;}
    public String? BlogTags {get; set;}
    
    
    }

}

And my Author class:

using System.ComponentModel.DataAnnotations;

namespace backend.Models
{
    public class Author : Times
    {
    [Key]
    public String AuthorId {get; set;}
    public String AuthorFirstName {get; set;}
    public String? AuthorMiddleName {get; set;}
    public String AuthorLastName {get;set;}
    public String? BriefDescription {get; set;}
    }
}

I've tried getting this to work with lazy loading and eager loading with the same results interestingly enough. I looked through some documentation and didn't see anything that would make me think this is a feature, but I'd be happy to be proven wrong.

Also, no clue why I', getting the $id: x fields in my json. Perhaps this is an artifact of using the Sqlite EF core package. If you know I'd love to know how I can fix this!

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
bzbz
  • 25
  • 1
  • 5
  • 1
    That's newtonsofts reference handling https://stackoverflow.com/questions/11542144/how-to-remove-id-during-json-serialization / https://www.newtonsoft.com/json/help/html/preserveobjectreferences.htm – Jeremy Lakeman Apr 06 '23 at 03:10
  • Do you mean if multiple `Blog` have the same `Author`, Even using `include(xx)` it will only load one `Author` entity in the first `Blog` instead of all ? – Xinran Shen Apr 06 '23 at 03:16
  • That's correct Xinran. I tested it and if I delete one of the existing blogs that has an author as shown in the json response, the next time I get the json response the other blog has the author. So it looks like it's only ever loading one distinct author in the query – bzbz Apr 06 '23 at 03:24
  • @XinranShen Each Blog item has a value set for Author property, but there is only one Author instance per author id. So the author instance is reused to have a smaller memory usage. – Sir Rufo Apr 06 '23 at 03:52

1 Answers1

0

I feel very silly. Both of my issues seemed to have been caused by this configuration in my Program.cs file:

builder.Services.AddControllers().AddJsonOptions(options => 
{
    options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.Preserve;

});

After looking at the documentation Jeremy Lakeman commented it all made sense. I've removed that configuration and replaced it with:

builder.Services.AddControllers();

Thank you for your help!

bzbz
  • 25
  • 1
  • 5