Create a Parent with existing children in EntityFramework core

asp.net-core entity-framework-core

Question

I am building a Web API and have two models: Task and Feature:

public class Feature
{
    [Key]
    public long FeatureId { get; set; }
    public string Analyst_comment { get; set; }

    public virtual ICollection<User_Task> Tasks { get; set; }

    public Feature()
    {

    }
}

public class User_Task
{
    [Key]
    public long TaskId { get; set; }
    public string What { get; set; }

    [ForeignKey("FeatureId")]
    public long? FeatureId { get; set; }


    public User_Task()
    {

    }

}

I create Tasks first and then create a Feature that combines few of them. Task creation is successful, however while creating a Feature with existing Tasks, my controller throws an error saying the task already exists:

My FeatureController has following method:

//Create
[HttpPost]
public IActionResult Create([FromBody] Feature item)
{
    if (item == null)
    {
        return BadRequest();
    }

    ** It basically expects that I am creating a Feature with brand new tasks, so I guess I will need some logic here to tell EF Core that incoming tasks with this feature already exist **

    _featureRepository.Add(item);

    return CreatedAtRoute("GetFeature", new { id = item.FeatureId }, item);
} 

How to tell EF core that incoming Feature has Tasks that already exist and it just needs to update the references instead of creating new ones?

My context:

public class WebAPIDataContext : DbContext
{
    public WebAPIDataContext(DbContextOptions<WebAPIDataContext> options)
        : base(options)
    {
    }

    public DbSet<User_Task> User_Tasks { get; set; }
    public DbSet<Feature> Features { get; set; }

}

And repo:

public void Add(Feature item)
{
    _context.Features.Add(item);
    _context.SaveChanges();
}
1
0
5/26/2017 10:13:57 AM

Popular Answer

When calling Add on a DBSet with a model that was not loaded from EF, it thinks it is untracked and will always assume it is new.

Instead, you need to load the existing record from the dbcontext and map the properties from the data passed into the API to the existing record. Typically that is a manual map from parameter object to domain. Then if you return an object back, you would map that new domain object to a DTO. You can use services like AutoMapper to map the domain to a DTO. When you're done mapping, you only need to call SaveChanges.

Generally speaking, loading the record and mapping the fields is a good thing for the security of your API. You wouldn't want to assume that the passed in data is pristine and honest. When you give the calling code access to all the properties of the entity, you may not be expecting them to change all the fields, and some of those fields could be sensitive.

0
5/30/2017 12:26:21 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow