简体   繁体   中英

Force reload of entity in Entity Framework after insert/add

I have a Project entity, defined as:

public class Project
{
    [Key]
    public Guid ProjectId { get; set; }
    //...
    [Required, ForeignKey("User")]
    public Guid UserId { get; set; }
    public virtual User User { get; set; }    
}

In my controller, I have:

// insert
public IHttpActionResult Post([FromBody] ProjectDTO projectDTO)
{
    return Save(projectDTO);
}

// update
public IHttpActionResult Post(Guid id, [FromBody] ProjectDTO projectDTO)
{
    return Save(projectDTO);
}

private IHttpActionResult Save(ProjectDTO projectDTO)
{
    if (!ModelState.IsValid)
        return BadRequest(ModelState);

    var isNew = projectDTO.ProjectId == Guid.Empty;

    Project project;
    if (isNew)
    {
        project = new Project();
        var user = UserManager.FindByName(User.Identity.Name);
        projectDTO.UserId = new Guid(user.UserId.ToString());

        DbContext.Entry(project).State = EntityState.Added;
    }
    else
    {
        project= DbContext.Projects.Find(projectDTO.ProjectId);
        if (project == null) return NotFound();

        DbContext.Entry(project).State = EntityState.Modified;
    }

    // set fields from DTO to User...

    DbContext.SaveChanges();

    // issue:

    return Ok(project);
}

The issue is that when a newly inserted project is returned by the controller, the virtual field User will be null because it hasn't been loaded/populated with the User data.

On the line // issue: I tried both of these lines:

if (isNew)
{
    // try one of these two lines:
    DbContext.Entry(project).Reload();
    project = DbContext.Projects.Find(project.ProjectId);
}

But both had no effect: I assume using the Find is not actually going back to the database because the entity already exists in the context, so it just returns that. But I would have thought the reload would have forced a full reload of the project with FK relationships, but it didn't.

I could do something like this:

if (isNew)
{
    project.User = DbContext.Users.Find(project.UserId);
}

But that doesn't look as clean as I'd like: I'd have to do it for each FK that I'm returning.

What's the best way to handle this?

You can detach it first, this should force the reloading upong finding:

DbContext.Entry(project).State = EntityState.Detached;
project = DbContext.Projects.Find(project.ProjectId);

If that doesn't work, you could detach it using the ObjectContext instead, but that will probably stop working on future versions of EF (where DbContext doesn't use ObjectContext ):

((IObjectContextAdapter)DbContext).ObjectContext.Detach(project);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM