Warm tip: This article is reproduced from stackoverflow.com, please click
asp.net entity-framework

EF core include multiple relations getting unwanted data

发布于 2020-03-31 23:00:32

I am a model relations as below

Post Model

public class Post : BaseEntity
    {
        public int Id { get; set; }
        public string Content { get; set; }
        public string Image { get; set; }

        public virtual User User { get; set; }
        [Column( "user_id" )] public string UserId { get; set; }

        public virtual  List< Comment > Comments { get; set; }
    }

User Model

public class User : IdentityUser
    {
        public string FirstName { get; set; }

        public string MiddleName { get; set; }

        public string LastName { get; set; }

        [Column( "created_at", Order = 254 )] public DateTime CreatedAt { get; set; }
        [Column( "updated_at", Order = 255 )] public DateTime UpdatedAt { get; set; }

        public virtual ICollection< Post > Posts { get; set; }
        public virtual ICollection< Comment > Comments { get; set; }
    }

Comment Model

public class Comment : BaseEntity
    {
        public int Id { get; set; }
        public string Content { get; set; }
        public virtual User User { get; set; }
        [Column( "user_id" )] public string UserId { get; set; }
        public virtual Post Post { get; set; }
        [Column( "post_id" )] public int PostId { get; set; }
    }

And when I do this

public IEnumerable< Post > GetAllPosts()
        {
            return dbContext.Posts
                .Include( post => post.User )
                .ThenInclude( post => post.Comments )
                .ToList();
        }

I get multiple depths of data. I only need one level of child

This is my output for just a post. The data is repeating itself.

[
    {
        "id": 5,
        "content": "This post is about fires going on in NSW",
        "image": null,
        "user": { 
            "firstName": "Bikram",
            "middleName": null,
            "lastName": "Bhandari",
            "createdAt": "0001-01-01T00:00:00",
            "updatedAt": "0001-01-01T00:00:00",
            "posts": [], --I don't want this
            "comments": [  -- Unwanted
                {
                    "id": 7,
                    "content": "So sad to see this",
                    "userId": "052b4889-431f-48d2-b673-5835166c03ee",
                    "postId": 5,
                    "createdAt": "0001-01-01T00:00:00",
                    "updatedAt": "0001-01-01T00:00:00"
                },
                {
                    "id": 8,
                    "content": "Let's hope for a rain",
                    "userId": "052b4889-431f-48d2-b673-5835166c03ee",
                    "postId": 5,
                    "createdAt": "0001-01-01T00:00:00",
                    "updatedAt": "0001-01-01T00:00:00"
                }
            ],
            "id": "052b4889-431f-48d2-b673-5835166c03ee",
            "userName": "bikrambhandari48@gmail.com",
            "normalizedUserName": "BIKRAMBHANDARI48@GMAIL.COM",
            "email": "bikrambhandari48@gmail.com",
            "normalizedEmail": "BIKRAMBHANDARI48@GMAIL.COM",
            "emailConfirmed": false,
            "passwordHash": "AQAAAAEAACcQAAAAEHBFj2Woq4/JhqyPWtaXt2xjL4+ML9XQR24pYJsvUAaAKWr/Pg4NgQ2S/O1h8fkerg==",
            "securityStamp": "XVNJKDOYMMT6SP2LLBUNHRKWGT3NZB4X",
            "concurrencyStamp": "2658eced-edd7-4458-b9e2-a010b46e3f37",
            "phoneNumber": null,
            "phoneNumberConfirmed": false,
            "twoFactorEnabled": false,
            "lockoutEnd": null,
            "lockoutEnabled": true,
            "accessFailedCount": 0
        },
        "userId": "052b4889-431f-48d2-b673-5835166c03ee",
        "comments": [
            {
                "id": 7,
                "content": "So sad to see this",
                "user": { --Not wanted
                    "firstName": "Bikram",
                    "middleName": null,
                    "lastName": "Bhandari",
                    "createdAt": "0001-01-01T00:00:00",
                    "updatedAt": "0001-01-01T00:00:00",
                    "posts": [],
                    "comments": [ --Not wanted
                        {
                            "id": 8,
                            "content": "Let's hope for a rain",
                            "userId": "052b4889-431f-48d2-b673-5835166c03ee",
                            "postId": 5,
                            "createdAt": "0001-01-01T00:00:00",
                            "updatedAt": "0001-01-01T00:00:00"
                        }
                    ],
                    "id": "052b4889-431f-48d2-b673-5835166c03ee",
                    "userName": "bikrambhandari48@gmail.com",
                    "normalizedUserName": "BIKRAMBHANDARI48@GMAIL.COM",
                    "email": "bikrambhandari48@gmail.com",
                    "normalizedEmail": "BIKRAMBHANDARI48@GMAIL.COM",
                    "emailConfirmed": false,
                    "passwordHash": "AQAAAAEAACcQAAAAEHBFj2Woq4/JhqyPWtaXt2xjL4+ML9XQR24pYJsvUAaAKWr/Pg4NgQ2S/O1h8fkerg==",
                    "securityStamp": "XVNJKDOYMMT6SP2LLBUNHRKWGT3NZB4X",
                    "concurrencyStamp": "2658eced-edd7-4458-b9e2-a010b46e3f37",
                    "phoneNumber": null,
                    "phoneNumberConfirmed": false,
                    "twoFactorEnabled": false,
                    "lockoutEnd": null,
                    "lockoutEnabled": true,
                    "accessFailedCount": 0
                },
                "userId": "052b4889-431f-48d2-b673-5835166c03ee",
                "postId": 5,
                "createdAt": "0001-01-01T00:00:00",
                "updatedAt": "0001-01-01T00:00:00"
            },
            { --Not wanted
                "id": 8,
                "content": "Let's hope for a rain",
                "user": {
                    "firstName": "Bikram",
                    "middleName": null,
                    "lastName": "Bhandari",
                    "createdAt": "0001-01-01T00:00:00",
                    "updatedAt": "0001-01-01T00:00:00",
                    "posts": [],
                    "comments": [
                        {
                            "id": 7,
                            "content": "So sad to see this",
                            "userId": "052b4889-431f-48d2-b673-5835166c03ee",
                            "postId": 5,
                            "createdAt": "0001-01-01T00:00:00",
                            "updatedAt": "0001-01-01T00:00:00"
                        }
                    ],
                    "id": "052b4889-431f-48d2-b673-5835166c03ee",
                    "userName": "bikrambhandari48@gmail.com",
                    "normalizedUserName": "BIKRAMBHANDARI48@GMAIL.COM",
                    "email": "bikrambhandari48@gmail.com",
                    "normalizedEmail": "BIKRAMBHANDARI48@GMAIL.COM",
                    "emailConfirmed": false,
                    "passwordHash": "AQAAAAEAACcQAAAAEHBFj2Woq4/JhqyPWtaXt2xjL4+ML9XQR24pYJsvUAaAKWr/Pg4NgQ2S/O1h8fkerg==",
                    "securityStamp": "XVNJKDOYMMT6SP2LLBUNHRKWGT3NZB4X",
                    "concurrencyStamp": "2658eced-edd7-4458-b9e2-a010b46e3f37",
                    "phoneNumber": null,
                    "phoneNumberConfirmed": false,
                    "twoFactorEnabled": false,
                    "lockoutEnd": null,
                    "lockoutEnabled": true,
                    "accessFailedCount": 0
                },
                "userId": "052b4889-431f-48d2-b673-5835166c03ee",
                "postId": 5,
                "createdAt": "0001-01-01T00:00:00",
                "updatedAt": "0001-01-01T00:00:00"
            }
        ],
        "createdAt": "0001-01-01T00:00:00",
        "updatedAt": "0001-01-01T00:00:00"
    }
]

If you see above you can see that the data are repeating itself. What am I doing wrong to retrieve all the posts and the user associated with the post and all the comments of a post? Can anybody suggest how should I define my model relations to better retrieve my data? I want to retrieve all the posts and comments from user's perspective too. And in the comments model, I want to know which post the comment belongs to and who is the owner of the comment too. Thank you in advance.

Questioner
Bikram
Viewed
64
David Browne - Microsoft 2020-01-31 22:00

The Change Tracker will fix-up releationships as it loads entities. So if you load a Post's comments, and you have already loaded the User for some of those comments, the Navigation Property between User and Comments will be set.

If change tracking is enabled, then when loading an entity, EF Core will automatically set the navigation properties of the newly-loaded entitiy to refer to any entities already loaded, and set the navigation properties of the already-loaded entities to refer to the newly-loaded entity.

Loading Related Data - EF Core: Explicit Loading

Disable Change Tracking on the DbContext to prevent this behavior,

public IList< Post > GetAllPosts()
{
    return dbContext.Posts.AsNoTracking()
        .Include( post => post.User )
        .ThenInclude( post => post.Comments )
        .ToList();
}

And return IList<T>, not IEnumerable<T>, otherwise your caller won't know whether this is a streaming result, and might defensively load the result into a list.

Alternatively specify the shape of the document in your JSON serializer.