quain
quain

Reputation: 984

What is the proper way of handling object reference when applying projections in EF Core?

Given following simple example of object:

public class Item 
{
    public int Id { get; set; }

    public string Description { get; set; }

    public Item ChildItem { get; set; }
}

Assume, that:

builder.HasOne(x => x.ChildItem)
    .WithMany()
    .IsRequired(false)
    .OnDelete(DeleteBehavior.Restrict);
public class ItemProjection 
{
    public int Id { get; set; }

    public ItemProjection ChildItem { get; set; }
}

I am trying to find out if there is a correct way of returning entities as projections.

Options that came to my mind are:

Mind that there are situations, where returned collection will contain parents that contain children and children by themselves as parents without children. In such situation first option also returns separate instances even though, at least in my mind, they should be the same instance.

Later in lifecycle of the application, those projections will be modified and translated back to entities.

Main question is - is there a preferred / proper way of handling such thing?

Upvotes: 0

Views: 308

Answers (1)

Steve Py
Steve Py

Reputation: 34908

The idea behind projecting is to provide a consumer what a consumer needs rather than everything the data can provide. Since projections are typically used in transport layers between the server/service and the consumer/client, this often involves things like serialization in which case worrying about single vs. multiple instances becomes a non-concern. The end consumer will almost invariably be receiving multiple instances, and returning multiple instances when that data is sent back to the server.

Projections should ideally limit the data to just what the consumer will need to see, and that can mean flattening data relationships if there is no real benefit to maintaining them. It could also mean that while your domain model might be normalized down to Item Item -> Item Child, your projected "child" doesn't need to expose everything that it's underlying "Item" has, (including it's own possible child) in which case you can consider:

ItemProjection
{
   Id,
    // ... Item Fields
   ChildId,
   ChildField
   // ...
}

or

ItemProjection
{
    Id,
    // ... Item Fields
    ChildProjection Child
}

Where ChildProjection is a separate definition specific to the data needed to represent a child in this relationship. (Not necessarily all of the "Item" fields)

Most often with 1..1 / 0..1 relationships I opt to flatten the projections where the number of fields I care about from the child(ren) are relatively few. For cases where I do need more detail from a child I will use a child projection. I'd only consider something like an ItemProjection Child in cases where my consumer specifically wants to build a self-referencing tree.

Upvotes: 2

Related Questions