Zapis danych do bazy danych - błąd 400

0

Próbuję dokończyć aplikację i właściwie został mi ostatni problem do rozwiązania, a mianowicie chciałbym zapisywać pewne zgłoszenie w bazie danych. Aplikacja łączy się z bazą przez API, gdzie encja która będzie zapisywana wygląda tak:

public class DefectsEntity
    {
        [Key]
        public int idDefect { get; set; }
        public string Number_notification { get; set; }
        public int IdRoad { get; set; }
        public int IdElement { get; set; }
        public int IdIntensity { get; set; }
        public string Description { get; set; }
        public string Recommendation { get; set; }
        public int IdUser { get; set; }
        public DateTime Notification_date { get; set; }
        public string IdPhoto { get; set; }
        public decimal Latitude { get; set; }
        public decimal Longititude { get; set; }
        
        public virtual ElementsEntity Elements { get; set; }
        public virtual RoadsEntity Roads { get; set; }
        public virtual IntensityEntity Intensity { get; set; }
        public virtual UsersEntity Users { get; set; }
        
        public DefectsEntity()
        {

        }
        public DefectsEntity(int idRoad, int idElement, int idIntensity, string description, string recommendation, int idUser, DateTime notification_date, string idPhoto, decimal latitude, decimal longititude,
            ElementsEntity element, RoadsEntity roads, IntensityEntity intensity, UsersEntity user)
        {
            IdRoad = idRoad;
            IdElement = idElement;
            IdIntensity = idIntensity;
            Description = description;
            Recommendation = recommendation;
            IdUser = idUser;
            Notification_date = notification_date;
            IdPhoto = idPhoto;
            Latitude = latitude;
            Longititude = longititude;
            Elements = element;
            Roads = roads;
            Intensity = intensity;
            Users = user;
        }

    }

W bazie danych dwie pierwsze kolumny (idDefect oraz Number_Notification) uzupełniane są automatycznie. Kontroler który obsługuje dodanie zgłoszenia:

[HttpPost]
        public IActionResult Create([FromBody]DefectsEntity defect)
        {
           
            try
            {
                if (defect == null || !ModelState.IsValid)
                {

                    return BadRequest(ErrorCode.TodoItemNameAndNotesRequired.ToString());
                }
                bool defectExists = _defectRepository.DoesItemExist(defect.idDefect);
                if (defectExists)
                {
                    return StatusCode(StatusCodes.Status409Conflict, ErrorCode.TodoItemIDInUse.ToString());
                }
                _defectRepository.Add(defect);
                _defectRepository.Save();
            }
            catch (Exception)
            {
                return BadRequest(ErrorCode.CouldNotCreateItem.ToString());
               
            }
            return Ok(defect);
        }

Po stronie aplikacji metoda komunikująca się z API w celu dodania zgłoszenia:

public async Task SaveDefectAsync(DefectEntity defect)
        {
            Uri uri = new Uri(string.Format(Constants.DefectsRestUrl, string.Empty));

            try
            {
                string json = JsonSerializer.Serialize<DefectEntity>(defect, serializerOptions);
                StringContent content = new StringContent(json, Encoding.UTF8, "application/json");

                HttpResponseMessage response = null;
                response = await client.PostAsync(uri, content);

                if (response.IsSuccessStatusCode)
                {
                    Debug.WriteLine(@"\tDefect successfully saved.");
                }
                else
                {
                    Debug.WriteLine(@"\tDefect failure");
                }

            }
            catch (Exception ex)
            {
                Debug.WriteLine(@"\tERROR {0}", ex.Message);
            }
        }

JSON który idzie z aplikacji do API:

{
  "idDefect": 0,
  "number_notification": null,
  "idRoad": 4,
  "idElement": 6,
  "idIntensity": 3,
  "description": "Gggf",
  "recommendation": "Xvfff",
  "idUser": 2,
  "notification_date": "2021-05-21T14:57:55.4151+02:00",
  "idPhoto": "995d7418-90cb-48b2-8784-4ed978c0981d.jpg",
  "latitude": 52.45641191,
  "longititude": 20.95981319,
  "roads": {
    "idRoad": 4,
    "number_road": "G877326P",
    "name_road": "Franciszka\u0144ska"
  },
  "elements": {
    "idElement": 6,
    "name_Element": "Wpust deszczowy"
  },
  "intensity": {
    "idIntensity": 3,
    "name_Intensity": "Du\u017Ca"
  },
  "users": {
    "idUser": 2,
    "nameUser": "Pawe\u0142",
    "surnameUser": "Mickiewicz",
    "email": "[email protected]"
  }
}

No i element nie dodaje się do bazy danych, zwracany jest błąd 400. Próbowałem z Postman ale skutek ten sam czyli podejrzewam że mam błąd po stronie API lub źle tworzę JSON. Dodawanie danych do innych tabel działa bez zarzutu, jednak ta jest bardziej złożona bo posiada klucze obce.

1

https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/400 - może pokaż to API bo wygląda, że tam jest coś nie tak.

0

@UglyMan: Pierwsze dwa bloki kodu są z API czyli klasa z encją reprezentującą tabele z bazy danych i Controller. Dorzucam jeszcze datacontext:

public class DatabaseContext:DbContext
    {
        public DbSet<DefectsEntity> Defects { get; set; }
        public DbSet<IntensityEntity> Intensity { get; set; }
        public DbSet<ElementsEntity> Elements { get; set; }
        public DbSet<RoadsEntity> Roads { get; set; }
        public DbSet<UsersEntity> Users { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            base.OnConfiguring(optionsBuilder);
            optionsBuilder.UseSqlServer("connetion string");

        }
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            modelBuilder.Entity<DefectsEntity>().HasOne(d => d.Intensity).WithMany().HasForeignKey(x => x.IdIntensity);
            modelBuilder.Entity<DefectsEntity>().HasOne(d => d.Roads).WithMany().HasForeignKey(x => x.IdRoad);
            modelBuilder.Entity<DefectsEntity>().HasOne(d => d.Elements).WithMany().HasForeignKey(x => x.IdElement);
            modelBuilder.Entity<DefectsEntity>().HasOne(d => d.Users).WithMany().HasForeignKey(x => x.IdUser);
        }
    }
0
"idDefect": 0

jesteś pewny ,że dawanie id 0 jest tutaj właściwe? Poza tym przydałby się kod od

_defectRepository.Add()
0

@Botek:

public class DefectDbRepository : IDefectRepository
    {
        private DatabaseContext dbContext = new DatabaseContext();
        public void Add(DefectsEntity defect)
        {
            dbContext.Defects.Add(defect);
        }
    }

I interface

public interface IDefectRepository
    {
        void Add(DefectsEntity defect);
    }
0

A sama metoda kontrolera się odpala? Bo to chyba nie jest problem kodu metody kontrolera.
Routing?

0

Ja osobiście mam wrażenie ,że klucze obce się gryzą. Sprawdź debugerem jakiego exceptiona dostajesz w catch. Moim zdaniem albo odwołujesz się do nieistniejącego klucza albo próbujesz ustawić klucz obcy na null gdzie jest on required , ale to trzeba sprawdzić debugerem. Ogólnie to taka uwaga na marginesie nie podoba mi się szczerze mówiąc wywoływanie Save jaka osobna metoda w kontrolerze według mnie to inna warstwa powinna się martwić czy zapisać czy nie a nie kontroler w ,którym powinno się minimalizować kod.

0

Jak dodajesz swój serwis w startup zmień z

services.AddSingleton<..>

na

 services.AddScoped<..>
0

@Botek: Zmieniłem. Dodatkowo zmodyfikowałem JSON:

{
  "idDefect": 0,
  "idRoad": 2,
  "idElement": 5,
  "idIntensity": 3,
  "description": "sdfsdfsd",
  "recommendation": "sdfdsfsdf",
  "idUser": 1,
  "notification_date": "2021-05-21T17:14:21.058009+00:00",
  "idPhoto": "146a3f46-74a4-40d1-9ef8-b4878ee6faf6.jpg",
  "latitude": 52.4079583333333,
  "longititude": 20.93965,
  "roads": null,
  "elements": null,
  "intensity": null,
  "users": null
}

Nie ustawiam roads, elements, intensity i users bo to się gryzło z wcześniej przekazywanymi kluczami obcymi.
Nadal nie zapisuje, ale teraz błąd jest następujący: "The column "Number_notification" cannot be modified because it is either a computed column or is the result of a UNION operator.". I faktycznie, ta kolumna w bazie danych wygląda tak:

[Number_notification]  AS (concat([idDefect],'/',datepart(month,[Notification_date]),'/',datepart(year,[Notification_date])))

Chciałem żeby tworzył się tu unikalny numer zgłoszenia

0

Mógłbyś pokazać ten fragment kodu ,który odpowiada za automatyczne generowanie Number_notification?

1 użytkowników online, w tym zalogowanych: 0, gości: 1