2

Post updated with solution.

Let's say i have two simple model classes to explain my problem. Each model as navigation properties for DB relationships. Everything it's ok with migrations creation and update-database, also with postman for GET endpoints. The problem... i can POST a User, but can't POST a Car record. I followed the Code First from Microsoft tutorial with Fluent API method, but i also tried with Data Annotations, but same result (between some other tests i also tried with 'virtual' keyword). A brief search pointed me to nested Object/Array upon doing the POST record to DB, but also no success, same error! This is a little example from my project with more than 6 model classes, but with this two i think i can explain my problem. This is for one-to-many relationship.

public class User
    {
        public int Id { get; set; }
        public string Age { get; set; }
        public string Name { get; set; }
        public string City { get; set; }
        public string Country { get; set; }

        // navigation property
        public List<Car> Cars { get; set; }
    }

And Car model:

public class Car
    {
        public int Id { get; set; }
        public int Year { get; set; }
        public string Plate { get; set; }

        // navigation property
        public int UserId { get; set; }
        public User User { get; set; }
    }

And here's the DbContext:

public MyPersonalProjectContext(DbContextOptions<MyPersonalProjectContext> options) : base(options)
        {
        }

        public DbSet<User> Users { get; set; }
        public DbSet<Car> Cars { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            // setting database relationships with constraints and cascade delete
            // one-to-many for User -> Car tables
            modelBuilder.Entity<Car>()
                .HasOne(u => u.User)
                .WithMany(c => c.Cars)
                .HasForeignKey(u => u.UserId)
                .HasConstraintName("FK_User_Cars")
                .OnDelete(DeleteBehavior.Cascade);
        }

I POST this example record in api/cars endpoint:

{
    "year": 2012,
    "plate": "YY-11-BB",
    "userId": 2
}

Postman gives me:

{
    "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
    "title": "One or more validation errors occurred.",
    "status": 400,
    "traceId": "00-36feeb71fcd60b67da499091bf94598a-1b14d3e2c48fc635-00",
    "errors": {
        "User": [
            "The User field is required."
        ]
    }
}

I also tried POSTing an empty array to try to cheat:

{
        "year": 2012,
        "plate": "YY-11-BB",
        "userId": 2,
        "user": []
    }

CarsController:

public async Task<ActionResult<Car>> PostCar(Car car)
        {
            if (_context.Cars == null)
            {
                return Problem("Entity set 'MyPersonalProjectContext.Cars'  is null.");
            }

            _context.Cars.Add(car);
            await _context.SaveChangesAsync();

            return CreatedAtAction("GetCar", new { id = car.Id }, car);
        }

[SOLUTION]: After some digging and try and error, i came up with the solution, at least for my case. I will post here what i've achieved so that many others with the same problem can solve it also!

Create a ModelDTO (for one who don't know what is, here's a good explanation from this 12 years old topic What is a Data Transfer Object (DTO)?)

public class CreateCarDTO
    {
        public int Id { get; set; }
        public int Year { get; set; }
        public string Plate { get; set; }
        public int UserId { get; set; }
    }

Then i've made a little changes in my controller POST method:

[HttpPost]
        public async Task<ActionResult<Car>> PostCar(CreateCarDTO request)
        {

            var user = await _context.Users.FindAsync(request.UserId);
            if (user == null)
            {
                return NotFound();
            }
            var newCar = new Car
            {
                Year = request.Year,
                Plate = request.Plate,
                User = user
            };

            _context.Cars.Add(newCar);
            await _context.SaveChangesAsync();
            return await GetCar(newCar.UserId);
        }

And finally for JSON exceptions, i added [JsonIgnore] in Model:

public class Car
    {
        public int Id { get; set; }
        public int Year { get; set; }
        public string Plate { get; set; }

        // navigation property for parent entity and foreign key
        // one-to-many car -> user
        public int UserId { get; set; }
        [JsonIgnore]
        public User User { get; set; }

    }

Hope this solution help others :-).

2
  • Can you share the code you have for the endpoint itself? Commented Jun 2, 2022 at 16:49
  • 1
    This looks like ef-core-6, not ef6 (classic). If so, please retag. Commented Jun 3, 2022 at 11:37

1 Answer 1

2

First of all If you want to save Cars without User you should Cars entity as below.

public class Car
{
    public int Id { get; set; }
    public int Year { get; set; }
    public string Plate { get; set; }

    // navigation property make nullable
    public int? UserId { get; set; }
    public User User { get; set; }
}

If you want to save with user in this case that User must exist in database. For example in your example User must exists in database with id=2

Sign up to request clarification or add additional context in comments.

5 Comments

My mistake when put code in comment, sorry. Yusif Karimov, also tried with your answer and have same ERROR. Can´t understand what's wrong. When I update-database I create seed data, so DB it's populated.
I tried to your code which you mentioned in up comment. And it worked. Like below { "year": 2023, "plate": "YY-99-BB", "userId": 1 } I used this request model. public async Task<ActionResult<Car>> PostCar(Car car) { try { if (_context.Cars == null) return Problem("Entity set 'MyPersonalProjectContext.Cars' is null."); _context.Cars.Add(car); await _context.SaveChangesAsync(); return CreatedAtAction("GetCar", new { id = car.Id }, car); } catch (Exception ex) { throw; } }
Did you check User table for Id = 2 ?
that is weird, could i have some error else where and i can't find it?! here's my seed data that proves my Id = 2 raoliveirablob.blob.core.windows.net/newcontainer/…
I can only made a POST if i nest the object like this.... And this is not acceptable for me. Also, Postman gives me the error for Json larger than the maximum allowed depth of 32, so i have to include JsonSerializerOptions in services to complete POST. { "year": 2012, "plate": "YY-11-BB", "userId": 10, "user": { "name": "asdas", "age": "15", "country": "pt", "city": "asasdf", "cars": [] }} raoliveirablob.blob.core.windows.net/newcontainer/…

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.