Search code examples
c#angularentity-frameworkentity-framework-coreasp.net-core-mvc

How to handle Entity Framework models with required navigation property for data transfer?


I have two tables in the database:

  • Configuration (parent)

    • id (PK)

    • Name

  • ConfigurationAlert (child)

    • id (PK)

    • ConfigurationId (PK, FK Configuration)

    • Message

I have generated the models for Entity Framework Core through scaffolding, using custom templates:

public partial class Configuration
{
    public int Id { get; set; }
    public string Name { get; set; } = null!;
    public virtual ICollection<ConfigurationAlert> ConfigurationAlerts { get; set; } = new List<ConfigurationAlert>();
}

public partial class ConfigurationAlert
{
    public int Id { get; set; }
    public int? ConfigurationId { get; set; }
    public string Message{ get; set; }
    public virtual Configuration ConfigurationIdNavigation { get; set; } = null!;
}

Client-side (Angular app) I retrieve all the configurations and their alerts via an HTTP call which reach the server and use the EF context to query the DB and returns the entities. The ConfigurationAlert entities returns to the client without the ConfigurationIdNavigation, and that's ok to me.

The problem is when I send back to the server the modified Configurations+ConfigurationAlerts, that I have the error "One or more errors occurred: ConfigurationAlerts[0].ConfigurationIdNavigation - The ConfigurationIdNavigation field is required."

I can resolve the problem making the ConfigurationIdNavigation nullable using the custom template:

public virtual Configuration? ConfigurationIdNavigation { get; set; } = null!;

But I don't think that is the correct solution so I'm looking for suggestions.

Should I duplicate the entity creating a ConfigurationViewModel and ConfigurationAlertViewModel and use them as DTO? (there are a lot of other models so it would be a lot of code)

Or?

Thank you in advance.


Solution

  • Should I duplicate the entity creating a ConfigurationViewModel and ConfigurationAlertViewModel and use them as DTO? (there are a lot of other models so it would be a lot of code)

    Well, according to your shared code snippet, description you are correct, making ConfigurationIdNavigation nullable is not the ideal solution as it introduces potential data integrity issues.

    According to the scenario, it can be resolved in either way.

    First of all, Instead of excluding the ConfigurationIdNavigation property when retrieving data, you can include it in your query. This ensures the navigation property is populated and avoids the error when saving changes. So we can do as following:

    var configurations = _context.Configurations
        .Include(c => c.ConfigurationAlerts)
        .ToList();
    

    Another way, you could consider, is to use view models or DTOs (Data Transfer Objects). Becuase, It decouples your database models from your API contract, allowing for better control over what data is sent to and received from clients. While it may involve some additional code, it offers benefits such as improved flexibility, reduced payload size, and enhanced security.

    In order to implement that, we could do as following:

    public class ConfigurationViewModel
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public List<ConfigurationAlertViewModel> ConfigurationAlerts { get; set; }
    }
    
    public class ConfigurationAlertViewModel
    {
        public int Id { get; set; }
        public string Message { get; set; }
    }
    

    Note: Point to keep in mind, when sending data to the client, map your database entities to view models. Also When receiving data from the client, map your view models back to database entities before saving them. Please refer to this official dcoument for additional resource.