C
C#8mo ago
chatrli

❔ Relationship validation

Here is my controller, feel free to navigate through the repo: https://github.com/chatrli/api_onotebook/blob/emails/Controllers/PeopleController.cs I added a relationship between my Person and Email models. Then I wrote a POST method to add an new email to a person by its id but i always the same error using postman and curl (with this route http://localhost:5062/people/1/emails)
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "00-5628679ef1a96e94cb3c5347f4417827-abfa0d432f9b4cbc-00",
"errors": {
"Person": [
"The Person field is required."
]
}
}
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "00-5628679ef1a96e94cb3c5347f4417827-abfa0d432f9b4cbc-00",
"errors": {
"Person": [
"The Person field is required."
]
}
}
I don't need the person field to be required actually I want to be able to have Person with no email and just register new email later. There is no Person + Email creation the same time. As I'm new to dotnet and have to be confortable with at least web api soon, I wish I can see how a simple relationship is used through the controller. Else if you have an explanation I will be glad. What I tried so far is making the Person field nullable in the Post method for create email but in comparison of other backend Im working with so far, it feels like a non sense.
c#
email.Person = null;
c#
email.Person = null;
When I said it feels like a non sense I mean that this should not require to be nullable? We should be able to just add a new email without creating a new Person, as on client side, there is 2 form. One for the Person and a second one for the Email that is in Person Detail page.
GitHub
api_onotebook/Controllers/PeopleController.cs at emails · chatrli/a...
Contribute to chatrli/api_onotebook development by creating an account on GitHub.
17 Replies
chatrli
chatrli8mo ago
Just for the example, here a row of Person:
json
{"id":1,"firstName":"John","middleName":null,"lastName":"Doe","birthDate":"2000-01-01 00:00:00","nationality":"American","nationalId":null,"currentPlace":null,"currentPosition":null,"isPubliclyWanted":false,"isPrivatlyWanted":false,"isDangerous":false,"emails":null}
json
{"id":1,"firstName":"John","middleName":null,"lastName":"Doe","birthDate":"2000-01-01 00:00:00","nationality":"American","nationalId":null,"currentPlace":null,"currentPosition":null,"isPubliclyWanted":false,"isPrivatlyWanted":false,"isDangerous":false,"emails":null}
Imo the relationship is ok. Maybe my POST method is wrong as it should be simple to append a new element in an array
JakenVeina
JakenVeina8mo ago
where does this exception throw?
chatrli
chatrli8mo ago
Hello thanks for the answer @V.EINA Jaken ! When I call the POST request for emails
JakenVeina
JakenVeina8mo ago
let's see it
chatrli
chatrli8mo ago
c#
[HttpPost("{id}/emails")]
public ActionResult AddEmailToPerson(int id, Email email)
{
var person = _context.People.Find(id);
if (person == null)
{
return NotFound("Not found");
}

email.PersonId = id;
_context.Emails.Add(email);
_context.SaveChanges();

return Ok(email);
}
c#
[HttpPost("{id}/emails")]
public ActionResult AddEmailToPerson(int id, Email email)
{
var person = _context.People.Find(id);
if (person == null)
{
return NotFound("Not found");
}

email.PersonId = id;
_context.Emails.Add(email);
_context.SaveChanges();

return Ok(email);
}
cause error:
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "00-5628679ef1a96e94cb3c5347f4417827-abfa0d432f9b4cbc-00",
"errors": {
"Person": [
"The Person field is required."
]
}
}
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "00-5628679ef1a96e94cb3c5347f4417827-abfa0d432f9b4cbc-00",
"errors": {
"Person": [
"The Person field is required."
]
}
}
According to my knowledge, if im not wrong this is a validation issue But I didn't seet any validation here as I want to be able to leave blank field is this possible to ask an api example if someone have one?
JakenVeina
JakenVeina8mo ago
so, the exception throws at _context.SaveChanges()?
chatrli
chatrli8mo ago
Exactly The model seems fine as I can see a null value when I get a record as seen below:
{"id":1,"firstName":"John","middleName":null,"lastName":"Doe","birthDate":"2000-01-01 00:00:00","nationality":"American","nationalId":null,"currentPlace":null,"currentPosition":null,"isPubliclyWanted":false,"isPrivatlyWanted":false,"isDangerous":false,"emails":null}
{"id":1,"firstName":"John","middleName":null,"lastName":"Doe","birthDate":"2000-01-01 00:00:00","nationality":"American","nationalId":null,"currentPlace":null,"currentPosition":null,"isPubliclyWanted":false,"isPrivatlyWanted":false,"isDangerous":false,"emails":null}
I believe the behavior is, I can't create a single email, i have to create a record(here person) and a email the same time. But the behavior I expect and need to do is, create an email on top of a record(here person)
JakenVeina
JakenVeina8mo ago
let's see the EF models, then somehow, you've written them to make the Person relationship required
chatrli
chatrli8mo ago
Person.cs
c#
using System.ComponentModel.DataAnnotations;

namespace api_os.Models {
public class Person {
[Key]
public int Id { get; set; }
public string? FirstName { get; set; }
public string? MiddleName { get; set; }
public string? LastName { get; set; }
public string? BirthDate { get; set; }
public string? Nationality { get; set; }
public int? NationalId { get; set; }
public string? CurrentPlace { get; set; }
public string? CurrentPosition { get; set; }
public bool IsPubliclyWanted { get; set; }
public bool IsPrivatlyWanted { get; set; }
public bool IsDangerous { get; set; }
public ICollection<Email> Emails { get; set; }
}
}
c#
using System.ComponentModel.DataAnnotations;

namespace api_os.Models {
public class Person {
[Key]
public int Id { get; set; }
public string? FirstName { get; set; }
public string? MiddleName { get; set; }
public string? LastName { get; set; }
public string? BirthDate { get; set; }
public string? Nationality { get; set; }
public int? NationalId { get; set; }
public string? CurrentPlace { get; set; }
public string? CurrentPosition { get; set; }
public bool IsPubliclyWanted { get; set; }
public bool IsPrivatlyWanted { get; set; }
public bool IsDangerous { get; set; }
public ICollection<Email> Emails { get; set; }
}
}
Email.cs
c#
using System.ComponentModel.DataAnnotations;

namespace api_os.Models
{
public class Email
{
[Key]
public int Id { get; set; }
public string EmailAddress { get; set; }
public int PersonId { get; set; }
public virtual Person Person { get; set; }
}
}
c#
using System.ComponentModel.DataAnnotations;

namespace api_os.Models
{
public class Email
{
[Key]
public int Id { get; set; }
public string EmailAddress { get; set; }
public int PersonId { get; set; }
public virtual Person Person { get; set; }
}
}
DatabaseContext.cs
c#
using Microsoft.EntityFrameworkCore;

namespace api_os.Models
{
public class DatabaseContext : DbContext
{
public DatabaseContext()
{
}
public DatabaseContext(DbContextOptions<DatabaseContext> options)
: base(options)
{
}

protected override void OnConfiguring(DbContextOptionsBuilder options)
{
if (!options.IsConfigured)
{
options.UseSqlite("Data Source=database.db");
}
}

public DbSet<Person> People { get; set; }
public DbSet<Email> Emails { get; set; }

protected override void OnModelCreating(ModelBuilder modelBuilder) {
modelBuilder.Entity<Email>()
.HasOne(e => e.Person)
.WithMany(p => p.Emails)
.HasForeignKey(e => e.PersonId);
}
}
}
c#
using Microsoft.EntityFrameworkCore;

namespace api_os.Models
{
public class DatabaseContext : DbContext
{
public DatabaseContext()
{
}
public DatabaseContext(DbContextOptions<DatabaseContext> options)
: base(options)
{
}

protected override void OnConfiguring(DbContextOptionsBuilder options)
{
if (!options.IsConfigured)
{
options.UseSqlite("Data Source=database.db");
}
}

public DbSet<Person> People { get; set; }
public DbSet<Email> Emails { get; set; }

protected override void OnModelCreating(ModelBuilder modelBuilder) {
modelBuilder.Entity<Email>()
.HasOne(e => e.Person)
.WithMany(p => p.Emails)
.HasForeignKey(e => e.PersonId);
}
}
}
JakenVeina
JakenVeina8mo ago
public class Email
{
[Key]
public int Id { get; set; }
public string EmailAddress { get; set; }
public int PersonId { get; set; }
public virtual Person Person { get; set; }
}
public class Email
{
[Key]
public int Id { get; set; }
public string EmailAddress { get; set; }
public int PersonId { get; set; }
public virtual Person Person { get; set; }
}
neither PersonId nor Person is nullable
chatrli
chatrli8mo ago
So I have to add interrogation mark to both?
JakenVeina
JakenVeina8mo ago
if you want it to be legal for them to be null, you have to specify that it's legal for them to be null, yes
chatrli
chatrli8mo ago
I'm testing it right now mate
JakenVeina
JakenVeina8mo ago
you'll need to rebuild your migrations, if you're using the designer
chatrli
chatrli8mo ago
yes, after migrations its different thanks a lot mate, I have a new error but it might be something i can troubleshoot System.Text.Json.JsonException: A possible object cycle was detected. This can either be due to a cycle or if the object depth is larger than the maximum allowed depth of 32. Consider using ReferenceHandler.Preserve on JsonSerializerOptions to support cycles. Path: $.Person.Emails.Person.Emails.Person.Emails.Person.Emails.Person.Emails.Person.Emails.Person.Emails.Person.Emails.Person.Emails.Person.Emails.Person.Id. anyway thanks amillion for that, just this ? mark make me struggling since yesterday Last question about the model if i may:
c#
public class Email
{
[Key]
public int Id { get; set; }
public string EmailAddress { get; set; }
public int PersonId { get; set; }
public virtual Person Person { get; set; }
}
c#
public class Email
{
[Key]
public int Id { get; set; }
public string EmailAddress { get; set; }
public int PersonId { get; set; }
public virtual Person Person { get; set; }
}
Here, if PersonId is nullable so PersonId? , the ide screams at me, asking to remove the getter and setter I need both nevermind i find the issue, i will use dto thanks a lot mate, have a great night 😃
JakenVeina
JakenVeina8mo ago
gg
Accord
Accord8mo ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.