0

I have two models which are related like following:

public class Context
    {
        [Key]
        public long ContextId { get; set; }
        [Required]
        public string Role { get; set; }

        public ICollection<Connection> Connections { get; set; }

        public Context()
        {

        }
    }

And

public class Connection
    {
        [Key]
        public long ConnectionId { get; set; }
        public string Name { get; set; }

        public long ContextId { get; set; }
        public Context Context { get; set; }

        public Connection()
        {

        }
    }

I have a repository for Context:

public class ContextRepository: IContextRepository
{
    private readonly WebAPIDataContext _db;

    public ContextRepository(WebAPIDataContext db)
    {
        _db = db;
    }

    public Context CreateContext(Context context)
    {
        _db.Contexts.Add(context);
        _db.SaveChanges();
        return context;
    }

    public void DeleteContext(long id)
    {
        Context context = GetContext(id);
        if (context != null)
        {
            _db.Contexts.Remove(context);
            _db.SaveChanges();
        }
    }

    public List<Context> GetAllContexts()
    {
        return _db.Contexts
            .Include(context => context.Connections)
            .ToList();
    }

    public Context GetContext(long id)
    {
        return _db.Contexts.FirstOrDefault(o => o.ContextId == id);
    }

    public void UpdateContext(long id, Context context)
    {
        Context contextToUpdate = _db.Contexts.FirstOrDefault(o => o.ContextId == id);
        contextToUpdate.Role = context.Role;
        contextToUpdate.Connections = context.Connections;
        _db.Update(contextToUpdate);
        _db.SaveChanges();

    }
}

Swagger gives me skeleton like following:

{
  "contextId": 0,
  "role": "string",
  "connections": [
    {
      "connectionId": 0,
      "name": "string",
      "contextId": 0,
      "context": {}
    }
  ]
}

If I fill "Role":"Worker" and "name":"Max" and do POST or similar in PUT then it gives me error:

{
  "Connections[0].Context.Role": [
    "The Role field is required."
  ]
}

Why is it so? I want to be able to POST or PUT data even if I do not fill connections related fields. Right now I have controller only for Context.

UPDATE: Controller:

[Route("api/[controller]")]
public class ContextController : Controller
{
    private readonly IContextRepository _contexts;
    public ContextController(IContextRepository contexts)
    {
        _contexts = contexts;
    }

    [HttpGet("")]
    public IActionResult GetAllContexts()
    {
        try
        {
            List<Context> contexts = _contexts.GetAllContexts();
            return Ok(contexts);
        }
        catch (EntityNotFoundException<Context>)
        {
            return NotFound();
        }

    }

    [HttpGet("{id}")]
    public IActionResult GetContext(long id)
    {
        Context context= _contexts.GetContext(id);
        if (context == null)
        {
            return NotFound();
        }
        return Ok(context);
    }

    [HttpPost]
    public IActionResult CreateContext([FromBody] Context context)
    {
        if (ModelState.IsValid == false)
        {
            return BadRequest(ModelState);
        }

        Context createdContext= _contexts.CreateContext(context);
        if (createdContext== null)
        {
            return NotFound();
        }
        return CreatedAtAction(
             nameof(GetContext), new { id = createdContext.ContextId}, createdContext);

    }

    [HttpPut("{id}")]
    public IActionResult UpdateContext(long id, [FromBody] Context context)
    {
        if (ModelState.IsValid == false)
        {
            return BadRequest(ModelState);
        }

        try
        {
            _contexts.UpdateContext(id, context);
            return Ok();
        }
        catch (EntityNotFoundException<Context>)
        {
            return NotFound();
        }
    }

    [HttpDelete("{id}")]
    public IActionResult DeleteCOntext(long id)
    {
        _contexts.DeleteContext(id);
        return Ok();
    }
}
Thinker
  • 5,326
  • 13
  • 61
  • 137
  • why you need context in your connection class when you have contextId, if you take out that will that works for you? – Turbot Mar 22 '17 at 14:05
  • This is my very first time with asp.net core and I was following tutorial of model relationships (https://learn.microsoft.com/en-us/ef/core/modeling/relationships), it was given there so. I am building Web Api, in that case this navigation property isn't needed? – Thinker Mar 22 '17 at 14:16
  • @Nitish Could you show me controller class? – Win Mar 22 '17 at 14:28
  • @Turbot I updated my question with controller. Also, if I removed context from connection, the error was gone. However, my update method in repo is still somehow wrong. If I try to PUT updated data in existing connection (in a specific context), it throws me error. – Thinker Mar 22 '17 at 14:34
  • Could you post the server exception? – Win Mar 22 '17 at 14:52
  • I got `An exception of type 'Microsoft.EntityFrameworkCore.DbUpdateException' occurred in Microsoft.EntityFrameworkCore.dll but was not handled in user code` So, There was a context with id=2, role="Manager" and it had a connection with id=5, name="Max". When I tried to PUT a request by changing name="Alex" and keeping everything else same, it gave me this error. – Thinker Mar 22 '17 at 14:56

1 Answers1

0

This is because you have missed virtual keyword in your relation fields. Here adding virtual keyword to Connections field in Context class

 public virtual ICollection<Connection> Connections { get; set; }

and to Context in Connection class will solve the issue

 public virtual Context Context { get; set; }

For more info read this anwser

Community
  • 1
  • 1
cpr43
  • 2,942
  • 1
  • 18
  • 18
  • Do I need to migrate and update database after adding virtual? Also, is `public virtual Context Context { get; set; }` at all necessary if I am building Web API (referring to first comment to my question)? – Thinker Mar 22 '17 at 17:51
  • dont think so ... actually it depends on your mappings .. have you mapped ContextId field in Connection as a foreign key in your db – cpr43 Mar 22 '17 at 17:56
  • No, not explicitly. See my models in questions, that's what you are referring to right? – Thinker Mar 22 '17 at 17:58
  • it will good if you put [ForeignKey("ContextId ")] attribute for the Context Field in connection – cpr43 Mar 22 '17 at 18:03
  • Okay, and do I really need `public Context Context { get; set; }` in connection if it's a web API? because only after removing it, I was able to get of the original error (see my comments below my question) – Thinker Mar 22 '17 at 18:06
  • if you use public virtual Context Context you will not have any ssues – cpr43 Mar 22 '17 at 18:08
  • Okay let me try this. – Thinker Mar 22 '17 at 18:10
  • Well, after doing this, I still got that error. I am not sure if it expects me to enter something in `"context": {}` If I remove Context from Connection I `"context": {}` this line goes away and so the error. – Thinker Mar 22 '17 at 18:38
  • You have added the foreign key constraint rigth?? – cpr43 Mar 22 '17 at 18:46
  • Yes I added that and did migrations, updated database. I have now `[ForeignKey("ContextId ")]public virtual Context Context { get; set; }` in my connection – Thinker Mar 22 '17 at 18:48