0

I have 2 model classes which looks like this:

public class Collection
{
    public int Id { get; set; }
    public int CenterId { get; set; }
    public string Reference { get; set; }

    public Status Status { get; set; }
}

public class Status
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
}

The statuses table is populated with 5 statuses. When I create a collection I would like to be able to attach the status to the collection. I have this BindingViewModel:

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

    [Required]
    [Display(Name = "Center id")]
    public int CenterId { get; set; }
    public string Reference { get; set; }

    public Status Status { get; set; }
}

When I call my controller, I would expect it to create the Collection with a foreign key pointing to the correct status. Instead it creates the status.... This is the code in the controller:

/// <summary>
/// Creates the collection
/// </summary>
/// <param name="model">The collection which is to be saved</param>
/// <returns>The collection that was saved to the database</returns>
[HttpPost]
[Route("")]
public IHttpActionResult Create(CollectionBindingModel model)
{

    // Save our collection
    return Save(model);
}

/// <summary>
/// Creates or updates the collection
/// </summary>
/// <param name="model">The collection which is to be saved</param>
/// <returns>The collection that was saved to the database</returns>
private IHttpActionResult Save(CollectionBindingModel model)
{
    // If our ModelState is invalid, return a bad request
    if (!ModelState.IsValid)
        return BadRequest(ModelState);

    // Assign our binding model to a new model
    var collection = new Collection()
    {
        Id = model.Id,
        CenterId = model.CenterId,
        Reference = model.Reference,
        Status = model.Status
    };

    // Save our collection
    if (collection.Id == 0)
        this.DbContext.Collections.Add(collection);
    else
        this.DbContext.Entry<Collection>(collection).State = EntityState.Modified;

    // Save the changes
    this.DbContext.SaveChanges();

    // Get the location header
    var locationHeader = new Uri(Url.Link("GetById", new { centerId = collection.CenterId, id = collection.Id }));

    // Return the result
    return Created(locationHeader, collection);
}

How can I get it to use the correct status that is already in the system?

4 Answers 4

2

You can use three approaches:

  1. If you want to add existing status to new collection you can get status from dbContext, based on data from viewmodel.

    var status = dbContext.Set().SingleOrDefault(s=>s.Id==model.Status.Id);

    collection.Status = status;

  2. you can attach your status from viewmodel to dbContext with method dbContext.Set<Status>.Attach(status), and then assign this attached status to your collection:

    dbContext.Set.Attach(model.Status);

    collection.Status = model.Status;

  3. you can add foreign key property StatusId to Collection entity and set this StatusId to Id of Status. And not set Status to Status property of collection.

    public class Collection
    {
    public int Id { get; set; }
    public int CenterId { get; set; }
    public string Reference { get; set; }        
    
    [ForeignKey("Status")]
    public int StatusId{get;set;}
    public Status Status { get; set; }
    }
    
Sign up to request clarification or add additional context in comments.

Comments

1

Even though I have marked Kirill with the correct answer, I thought i would post what I have actually done. I kept all my models the same, the only thing I changed was in my Save function. I changed the status to this:

// Assign our binding model to a new model
var collection = new Collection()
{
    Id = model.Id,
    CenterId = model.CenterId,
    Reference = model.Reference,
    Status = this.DbContext.Statuses.Attach(model.Status)
};

and that has worked.

Comments

0

The status object you get in the post is a new object, created by the binding. You should place the status id in the viewModel and load the corresponding status object from the db and reference that in the new collection:

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

    [Required]
    [Display(Name = "Center id")]
    public int CenterId { get; set; }
    public string Reference { get; set; }
    public string StatusName {get; set;}
    **public int StatusId { get; set; }**
}

maybe you have to use a hidden field in the view to roundtrip the value of the id.

Comments

0

It believes the Status object you pass along is a new one thus it will re-add it.

Fixes:

  1. Load the Status from the database even though you already have it. This will cause the returned Status object to be attached to the DbContext and you can just use that.

  2. Manually attach the Status object using context.Statuses.Attach(model.Status)

Both of these approaches will cause your model.Status object to become attached (and thus tracked).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.