Witam chciałem dodać jedną opcję do panelu administratora i w momencie kiedy próbuję usunąć użytkownika wyskakuje błąd jak na załączonym screenie. Na pewno coś nie do końca dobrze zrobiłem w zarządzaniu bazą. Jak rozwiązać ten problem?
http://pastebin.com/raw/k1paxPVm BillingAddress
http://pastebin.com/raw/1Q7EhXKq Cart
http://pastebin.com/raw/zPZXdajF CartItem
http://pastebin.com/raw/W0qmBuSP Customer
http://pastebin.com/raw/KY4i6zyW CustomerOrder
http://pastebin.com/raw/JGVMLPND ShippingAddress
http://pastebin.com/raw/AeWMQCzi Users
http://pastebin.com/raw/vsbKs3BQ AdminCustomer
Musisz ustawić sobie Cascade skoro chcesz tak kasować. Bo teraz próbujesz kasować coś co jest kluczem obcym i baza nie wie co zrobić. Wyobraź sobie że ten Użytkownik jest z czymś powiązany, hocby z zamówieniem. Co sie ma stać z zamówieniem jeśli usuwasz uzytkownika? Czy wszystkie powiązane zamówienia też maja zostać usunięte?
Wszystko ma być usunięte, każde powiązanie użytkownika
A więc tak zmodyfikowałem klasę Cart (http://pastebin.com/raw/kHd5rD9c), w pozostałych zmieniłem z cascadetype.all na remove. Błąd pozostaje ten sam i dodatkowo z bazy kasuje się tylko customer, user pozostaje nie zmieniony. Po usunięciu użytkownika dalej widnieje on w bazie i da się na jego dane zalogować do sklepu.
Ja tutaj widzę taki problem że nigdzie nie masz mappedBy a wszystkie relacje są bidirectional. Tak nie wolno. Musisz określić która strona jest "właścicielem" relacji.
MappedBy jest w klasie Cart, wiem że w którymś fragmencie czegoś nie dowiązałem, tylko nie potrafię się odnaleźć.
No ale gdzie? Wchodze na customera który ma powiazanie z Cart a mappedBy nie ma. Tak samo dla wszystkich innych OneToOne.
Dobra postaram się to poprawić
Już prawie wszystko działa( użytkownicy kasują się całkowicie z bazy tak jak sobie założyłem), tylko przy usuwaniu jednego użytkownika wystąpił błąd(w załączniku)
@Entity
public class BillingAddress implements Serializable {
private static final long serialVersionUID = -6091579459463730482L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int billingAddressId;
private String streetName;
private String streetNumber;
private String city;
private String country;
private String zipCode;
@OneToOne(cascade = CascadeType.REMOVE)
private Customer customer;
@Entity
public class CustomerOrder implements Serializable {
private static final long serialVersionUID = -1546649310334411202L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int customerOrderId;
@OneToOne(cascade = CascadeType.REMOVE)
@JoinColumn(name = "cartId")
private Cart cart;
@OneToOne(cascade = CascadeType.REMOVE)
@JoinColumn(name = "customerId")
private Customer customer;
@OneToOne(cascade = CascadeType.REMOVE)
@JoinColumn(name = "billingAddressId")
private BillingAddress billingAddress;
@OneToOne(cascade = CascadeType.REMOVE)
@JoinColumn(name = "shippingAddressId")
private ShippingAddress shippingAddress;
@Entity
public class Cart implements Serializable {
private static final long serialVersionUID = -4045729241960416615L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int cartId;
@OneToOne(cascade = CascadeType.REMOVE)
@JoinColumn(name = "customerId")
@JsonIgnore
private Customer customer;
@OneToMany(mappedBy = "cart", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private List<CartItem> cartItems;
@Entity
public class CartItem implements Serializable {
private static final long serialVersionUID = -4314427089896169685L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int cartItemId;
@ManyToOne()
@JoinColumn(name = "cartId")
@JsonIgnore
private Cart cart;
@ManyToOne()
@JoinColumn(name = "productId")
private Product product;
@Entity
public class Customer implements Serializable {
private static final long serialVersionUID = 5140900014886997914L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int customerId;
@NotEmpty(message = "Nazwa użytkownika nie może pozostać pusta!")
private String customerName;
@NotEmpty(message = "Uzupełnij adres email!")
private String customerEmail;
private String customerPhone;
@NotEmpty(message = "Nazwa użytkownika nie może pozostać pusta!")
private String username;
@NotEmpty(message = "Uzupełnij hasło!")
@Size(min = 6, max = 16, message = "Hasło musi zawierać od 6 do 16 znaków!")
private String password;
private boolean enabled;
@OneToOne(cascade = CascadeType.REMOVE, mappedBy = "customer")
@JoinColumn(name = "billingAddressId")
private BillingAddress billingAddress;
@OneToOne(cascade = CascadeType.REMOVE, mappedBy = "customer")
@JoinColumn(name = "shippingAddressId")
private ShippingAddress shippingAddress;
@OneToOne(cascade = CascadeType.REMOVE, mappedBy = "customer")
@JoinColumn(name = "cartId")
@JsonIgnore
private Cart cart;
@Entity
public class ShippingAddress implements Serializable {
private static final long serialVersionUID = 989191150380037359L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int shippingAddressId;
private String streetName;
private String streetNumber;
private String city;
private String country;
private String zipCode;
@OneToOne(cascade = CascadeType.REMOVE)
private Customer customer;
Późna godzina ale na oko usuwasz "w złym kierunku". Tzn masz BillingAddress bez powiązania (z tej strony) do CustomerOrder, więc jednocześnie nie ma z tej strony kaskady na delete. Więc próba usunięcia BillingAddress nie powoduje automatycznego kasowania CustomerOrderów z takim adresem tylko wywala constraint violation. Jakbyś usuwał najpierw CustomerOrder to by poszło bo w tą stronę masz kaskadę ustawioną.
QuickFix -> dodaj powiazanie OneToOne także od strony BillingAddress, ustaw kaskade i mappedBy.
Wszystko już działa jak powinno, dziękuję za wszystkie wskazówki
Za wcześnie się ucieszyłem, po modyfikacji BillingAddress (http://pastebin.com/raw/DkY61Ka2), poprzedni problem przestał występować, ale użytkownicy przestali się usuwać z tabeli authoritites i users.
@Entity
public class Customer implements Serializable {
private static final long serialVersionUID = 5140900014886997914L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int customerId;
@NotEmpty(message = "Nazwa użytkownika nie może pozostać pusta!")
private String customerName;
@NotEmpty(message = "Uzupełnij adres email!")
private String customerEmail;
private String customerPhone;
@NotEmpty(message = "Nazwa użytkownika nie może pozostać pusta!")
private String username;
@NotEmpty(message = "Uzupełnij hasło!")
@Size(min = 6, max = 16, message = "Hasło musi zawierać od 6 do 16 znaków!")
private String password;
private boolean enabled;
@OneToOne(cascade = CascadeType.REMOVE, mappedBy = "customer")
@JoinColumn(name = "billingAddressId")
private BillingAddress billingAddress;
@OneToOne(cascade = CascadeType.REMOVE, mappedBy = "customer")
@JoinColumn(name = "shippingAddressId")
private ShippingAddress shippingAddress;
@OneToOne(cascade = CascadeType.REMOVE, mappedBy = "customer")
@JoinColumn(name = "cartId")
@JsonIgnore
private Cart cart;
@Entity
public class Users {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int usersId;
private String username;
private String password;
private Boolean enabled;
private int customerId;
@Entity
public class Authorities {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int authoritiesId;
private String username;
private String authority;
Ja nie widzę tu żadnego powiązania więc nie bardzo rozumiem czemu mieliby się usuwać.
Dodałem takie powiązania, jednak nie przyniosło to zamierzonego efektu
@Entity
public class Authorities {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int authoritiesId;
private String username;
private String authority;
@OneToOne(cascade = CascadeType.ALL)
private Customer customer;
public class Users {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int usersId;
private String username;
private String password;
private Boolean enabled;
private int customerId;
@OneToOne(cascade = CascadeType.ALL)
private Customer customer;
@Entity
public class Customer implements Serializable {
private static final long serialVersionUID = 5140900014886997914L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int customerId;
@NotEmpty(message = "Nazwa użytkownika nie może pozostać pusta!")
private String customerName;
@NotEmpty(message = "Uzupełnij adres email!")
private String customerEmail;
private String customerPhone;
@NotEmpty(message = "Nazwa użytkownika nie może pozostać pusta!")
private String username;
@NotEmpty(message = "Uzupełnij hasło!")
@Size(min = 6, max = 16, message = "Hasło musi zawierać od 6 do 16 znaków!")
private String password;
private boolean enabled;
@OneToOne(cascade = CascadeType.REMOVE, mappedBy = "customer")
@JoinColumn(name = "billingAddressId")
private BillingAddress billingAddress;
@OneToOne(cascade = CascadeType.REMOVE, mappedBy = "customer")
@JoinColumn(name = "shippingAddressId")
private ShippingAddress shippingAddress;
@OneToOne(cascade = CascadeType.REMOVE, mappedBy = "customer")
@JoinColumn(name = "cartId")
@JsonIgnore
private Cart cart;
@OneToOne(cascade = CascadeType.ALL, mappedBy = "customer")
@JoinColumn(name = "usersId")
private Users users;
@OneToOne(cascade = CascadeType.ALL, mappedBy = "customer")
@JoinColumn(name = "authoritiesId")
private Authorities authorities;
No i co teraz próbujesz usuwasz i co się dzieje?
Użytkownicy nie usuwają się z tabel users i authorities. Nic poza wcześniejszymi działaniami się nie dzieje.
OMG ale KIEDY SIĘ NIE USUWAJĄ? Co próbujesz usuwać i uważasz że powinni się usunąć a się nie usuwają? o_O Bo generalnie ta funkcjonalność "działa" więc jeśli nie działa u ciebie to znaczy ze to TY robisz coś źle. Na przykład oczekujesz że zniknie rekord który wcale zniknąć nie powinien.
No więc tak, rejestruję nowego użytkownika, ma swoją nazwę, emaila i tak dalej. Pojawia się on w bazie danych w tabelach customer, users i authorities. Kiedy jako administrator usuwam danego customera, znika on jednocześnie z tabeli customer w bazie danych. Ale nadal mogę zalogować na jego nazwę i hasło tak jak wcześniej, dlatego zależy mi na usunięciu danych z wczśniej wymienionych tabel.
Masz jakieś pole customerId po stronie Users, a dodatkowo duplikujesz pola, to się dobrze nie skończy. Swoją drogą nie rozumiem czemu wszędzie dajesz @JoinColumn
, lubisz mieć dużo zbędnego kodu i większą szansę na popełnienie błędu, czy jak?
Staram się napisać swój pierwszy projekt w springu, więc jest możliwość że gdzieś popełniam błąd. W zasadzie wszystko co sobie założyłem fukcjonuje poprawnie z wyjątkiem poruszonego tutaj tematu, stąd moje ciągłe pytania.
A masz w bazie na kluczach obcych "ON DELETE CASCADE"?
On Delete Restrict