Oskar Dudycz

Pragmatycznie o programowaniu

Błąd "Cannot update a parent row a foreign key constraint fails" przy pobieraniu rekordów w NHibernate

2011-10-06 oskar dudycz.NET

cover

Dzisiaj kolejny krótki wpis, ponownie dotyczący NHibernate’a.

Jak pewnie zdążyliście zauważyć jest to coś co ostatnio sprawia mi najwięcej problemów.

Próbując pobrać rekordy przy pomocy zwykłego selecta zawężonego o kryteria w NHibernate, otrzymałem zaskakujący błąd.

"Cannot update a parent row: a foreign key constraint fails"

Pierwsza moja myśl była: “Pobieram rekordy, a on chce robić update? Jak to, zgłupiał?!”.

Miałem klasę zdefiniowaną jako:

public class KontoBankowe
{
    public virtual int    Id                 { get; set; }
    public virtual int    Oprocentowanie     { get; set; }
    public virtual int    IdBanku            { get; set; }
}

oraz mapowanie klasy jako:

public class KontoBankoweMapowanie : ClassMap<KontoBankowe>
{
    public KontoBankoweMapowanie()
    {
        Table("KontoBankowe");
        Id(e => e.Id);
        Map(e => e.Oprocentowanie, "Nazwisko").Not.Nullable();
        Map(e => e.IdBanku , "IdBanku ");
    }
}

Widzicie już co jest źle? Jeżeli tak, to bardzo Wam gratuluję, bo mnie to chwilę zajęło.

Dla równie opornych na wiedzę jak ja, tłumaczenie:

  1. Pobieramy wiersze konta bankowego.
  2. Wśród rekordów mamy wiersze, które w kolumnie IdBanku mają nulle (tabela i mapowanie na to pozwalają).
  3. Po pobraniu nulla NHibernate ustawia wartość właściwości IdBanku klasy KontoBankowe jako domyślna wartość typu int, czyli 0.
  4. Ponieważ encja pobrana przez nas jest różna od tej, która jest w bazie (0, zamiast null) to NHibernate przy wywołaniu metody Session.Flush() próbuje uaktualnić pobrany rekord. Nie istnieje, żaden bank o id równym 0, więc update wyrzuca błąd na kluczu obcym łączącym tabelę KontoBankowe z tabelą Bank.

Rozwiązanie problemu jest proste. Wystarczy w klasie KontoBankowe ustawić pole IdBanku jako int ?. Po poprawkach klasa będzie wyglądała:

public class KontoBankowe
{
    public virtual int    Id                 { get; set; }
    public virtual int    Oprocentowanie     { get; set; }
    public virtual int ?  IdBanku            { get; set; }
}

Do zapamiętania: Zawsze sprawdzać czy ustalone pole jako nullable jest typem, który może przyjąć wartości null (ze szczególnym uwzględnieniem typów prostych i struktur).

👋 If you found this article helpful and want to get notification about the next one, subscribe to Architecture Weekly.

✉️ Join over 5000 subscribers, get the best resources to boost your skills, and stay updated with Software Architecture trends!

Loading...
Event-Driven by Oskar Dudycz
Oskar Dudycz For over 15 years, I have been creating IT systems close to the business. I started my career when StackOverflow didn't exist yet. I am a programmer, technical leader, architect. I like to create well-thought-out systems, tools and frameworks that are used in production and make people's lives easier. I believe Event Sourcing, CQRS, and in general, Event-Driven Architectures are a good foundation by which this can be achieved.