Zapis danych do bazy danych - błąd 400

Zapis danych do bazy danych - błąd 400
Adrian Rostecki
  • Rejestracja:ponad 7 lat
  • Ostatnio:ponad 3 lata
  • Postów:11
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:

Kopiuj
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:

Kopiuj
[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:

Kopiuj
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:

Kopiuj
{
  "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": "p_mickiewicz@testdomain.onmicrosoft.com"
  }
}

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.

UglyMan
  • Rejestracja:około 6 lat
  • Ostatnio:około 3 lata
  • Postów:2206
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.

Adrian Rostecki
  • Rejestracja:ponad 7 lat
  • Ostatnio:ponad 3 lata
  • Postów:11
0

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

Kopiuj
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);
        }
    }
BO
  • Rejestracja:około 6 lat
  • Ostatnio:około 14 godzin
  • Postów:214
0
Kopiuj
"idDefect": 0

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

Kopiuj
_defectRepository.Add()
edytowany 6x, ostatnio: Botek
Adrian Rostecki
Na Postman próbowałem wysyłać bez idDefect, bo właściwie w bazie samo jest nadawane, ale efekt bez zmian. W dodatku jak zapisuje dane do innej tabeli, aplikacja też wysyła id tego obiektu jako 0 a mimo to obiekt jest zapisywany
Adrian Rostecki
  • Rejestracja:ponad 7 lat
  • Ostatnio:ponad 3 lata
  • Postów:11
0

@Botek:

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

I interface

Kopiuj
public interface IDefectRepository
    {
        void Add(DefectsEntity defect);
    }
JP
  • Rejestracja:ponad 7 lat
  • Ostatnio:4 miesiące
  • Postów:1065
0

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

Adrian Rostecki
Sprawdzałem, metoda w kontrolerze odpala się
JP
Aaa, sorry Nie doczytałem, że to Ty ,zwracasz http 400.
BO
  • Rejestracja:około 6 lat
  • Ostatnio:około 14 godzin
  • Postów:214
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.

edytowany 4x, ostatnio: Botek
Adrian Rostecki
Catch zwraca taki błąd: "The instance of entity type 'ElementsEntity' cannot be tracked because another instance with the same key value for {'idElement'} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting key values."
BO
  • Rejestracja:około 6 lat
  • Ostatnio:około 14 godzin
  • Postów:214
0

Jak dodajesz swój serwis w startup zmień z

Kopiuj
services.AddSingleton<..>

na

Kopiuj
 services.AddScoped<..>
edytowany 1x, ostatnio: Botek
Adrian Rostecki
  • Rejestracja:ponad 7 lat
  • Ostatnio:ponad 3 lata
  • Postów:11
0

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

Kopiuj
{
  "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:

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

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

BO
Tak na marginesie nie do końca rozumiem koncepcje, skoro numer ma być unikalny to nie może być od razu kluczem głównym?
Adrian Rostecki
Właściwie mógłby, dopiero teraz to sobie uświadomiłem
BO
  • Rejestracja:około 6 lat
  • Ostatnio:około 14 godzin
  • Postów:214
0

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

Adrian Rostecki
To dzieje się po stronie bazy danych: [Number_notification] AS (concat([idDefect],'/',datepart(month,[Notification_date]),'/',datepart(year,[Notification_date]))). Przy dodawaniu nowego zgłoszenia generuje się automatycznie
BO
Nie rozumiem idei generowania bazy w podejściu codefirst bo w takim generujesz nie? I jednocześnie wprowadzanie funkcji bezpośrednio w bazie mimo tego ,że da się to zrobić w EF
Adrian Rostecki
Racja, faktycznie to nie był najlepszy pomysł. Wyrzucę to z bazy i zobaczę czy wtedy się uda
BO
  • Rejestracja:około 6 lat
  • Ostatnio:około 14 godzin
  • Postów:214
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)