2013-10-01 3 views
1

Я читал много руководств о связях весны-гибернации, но я немного смущен о том, как их использовать в моем случае ... У меня есть объекты продукта/категории, определенные следующим образом:Spring Hibernate product - category relationship

Продукт

@Id 
@GeneratedValue(strategy = GenerationType.AUTO) 
@Column 
private int id; 


@Column 
private int category; 
. 
. 
. 

Категория

@Id 
@GeneratedValue(strategy = GenerationType.AUTO) 
@Column 
private int id; 

@NotEmpty 
@Column 
@Size (max = 25) 
private String name; 
. 
. 
. 

Так что, я бы лик e на странице списка продуктов под голосовой «категорией» появится название категории, а в форме продукта список категорий ... В моем случае продукт подходит только для одной категории, поэтому, если я прав, он должен быть @ManyToOne, но я не знаю, как реализовать это ... в моей базе данных продукта. У меня есть поле categoryId, но если я помечаю поле сущности категории как @OneToMany, оно не будет сохранено в db ...

EDIT Я изменил, как это (как было предложено): Product.class

@Table(name = "products") 
public class Product { 
    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    @Column 
    private int id; 

    @NotEmpty 
    @Column 
    @Size (max = 25) 
    private String name; 

    @Column 
    @Size (max = 255) 
    private String description; 


    @ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL) 
    @JoinColumn(name = "category_id", nullable = false) 
    private Category category; 

Category.class

@Entity 
@Table(name = "categories") 
public class Category { 

    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    @Column 
    private int id; 

    @NotEmpty 
    @Column 
    @Size (max = 25) 
    private String name; 


    @Column 
    @Size (max = 255) 
    private String description; 


    //Here mappedBy indicates that the owner is in the other side 
    @OneToMany(fetch = FetchType.EAGER, mappedBy = "category", cascade = CascadeType.ALL) 
    private Set<Product> products = new HashSet<Product>(); 

Контроллер

@RequestMapping(value = "/add/", method = RequestMethod.POST) 
    public String addProduct(
      @ModelAttribute(value = "product") @Valid Product product, 
      BindingResult result, ModelMap model, Category category) { 




     if (result.hasErrors()) { 
      return "forms/productForm"; 
     } 

     try { 
      category.addProduct(product); 
      product.setCategory(category); 

      // Add product to db 
      productService.addProduct(product); 

     } catch (Exception e) { 
      log.error("/add/---" + e); 
      return "redirect:/product/deniedAction/?code=0"; 
     } 

     return "redirect:/admin/product/"; 

    } 

Я также добавил @initbinder на контроллере продукта, чтобы перевести данные из вида продукта строки к категории ... но теперь, когда Я сохраняю продукт, который автоматически сохраняет категорию вместо прикрепления существующего выбранного ...

ответ

0

, так что у вас есть:

Product{ 
    atributtes... 
    @ManyToOne 
    Category category; --so every product has a category 
    } 

    Category { 
    attributtes... 
    @OneToMany(cascade=CascadeType.ALL) 
    @JoinColumn(name="id_Product") 
    private List<Product> products; 
    } 

попробовать это, если мы не можем посмотреть другое решение ..

0

Вы, кажется, имеют отношение один-ко-многим между категорией и продуктом (одна категории имеет много продуктов)

В Java (и вообще OO) вы ожидаете, что класс Category будет содержать список продуктов, поэтому категорию можно назвать «собственными» продуктами.

В SQL это наоборот: вы могли бы ожидать, что таблица продуктов будет содержать ссылку на внешний ключ для категории, поэтому здесь можно сказать, что Продукт можно назвать «собственной» категорией.

Похоже, вы используете JPA, чтобы вы могли иметь что-то вроде этого:

Категория Класс:

@Entity 
public class Category { 

    //other stuff... 

    @OneToMany(cascade=CascadeType.ALL, mappedBy="category") 
    private Set<Product> products; 

} 

Класс продукта:

@Entity 
public class Product { 

    //other stuff... 

    @ManyToOne 
    private Category category; 
} 
+0

Отлично! Это недостающая часть, в которой я нуждался! Кстати, мне нужно удалить идентификатор категории из таблицы db продукта? И ... есть ли я изменить категорию db один? –

+0

Вам не нужно создавать таблицы самостоятельно. Спящий режим может сделать это для вас - схема создается аннотациями (при необходимости) при ее запуске. Если у вас уже есть данные, которые необходимо сохранить, я предлагаю удалить все таблицы, запустить код, а затем проверить только что созданные таблицы и ограничения FK, чтобы убедиться, что они такие, как вы ожидали. – NickJ

+0

Я думаю, что hibernate делает это для меня, если я объявляю auto.dll –

0

Вы правы, вы должны использовать @ ManyToOne, потому что «... продукт подходит только для одной категории ...».

В объекте продукта объявить поле категории вместо категории int и аннотировать его с помощью @ManyToOne. Также добавьте @JoinColumn, чтобы указать имя столбца product.category_id в базе данных.

Продукт:

@Id 
@GeneratedValue(strategy = GenerationType.AUTO) 
@Column 
private int id; 


@ManyToOne 
@JoinColumn(name = "category_id") 
private Category category; 
. 
. 
. 
1

Как Product будет иметь только одну категорию и Category будет иметь список продуктов, вы можете связать эти два, создавая Foreign Key в таблице Product, чтобы обратиться к первичному ключ в таблице Категория:

Category Table: id, name, other fields... 
Product Table: id, category_id (FK), and other fields. 

а отображение может быть определено, как показано ниже:

public class Category { 

//Here mappedBy indicates that the owner is in the other side 
@OneToMany(fetch = FetchType.LAZY, mappedBy = "category", cascade = CascadeType.ALL) 
private Set<Product> products = new HashSet<Product>(); 
... 
} 


public class Product { 

//Here JoinColumn states that this entity is the owner of the relationship 
@ManyToOne(fetch = FetchType.LAZY) 
@JoinColumn(name = "category_id", nullable = false) 
private Category category; 
... 
} 

Атрибут mappedBy сообщает Hibernate, что коллекция является зеркальным отображением ассоциации «один-на-один» с другой стороны. Это похоже на Hibernate, что он должен распространять изменения, сделанные на конце ассоциации Product, в базу данных, игнорируя изменения, внесенные только в коллекцию products, которая у вас есть в Category. Таким образом, если мы вызываем только category.getProducts().add(product), никакие изменения не будут выполняться постоянно. Поскольку ассоциация является двунаправленной, вам необходимо создать ссылку с двух сторон, а не только одну.

Для вашего удобства, вы можете добавить один addProduct метод в Category классе, чтобы сохранить ассоциацию:

public void addProduct(Product product) { 
     product.setCategory(this); 
     products.add(product); 
} 
+0

Спасибо за вашу помощь, я внедрил вашу версию и, похоже, работает ... теперь у меня есть другой вопрос: в форме продукта я выбираю категорию с «option» box ... как я могу сохранить его в поле категории продукта db table_id? –

+0

И как отобразить правильное название категории внутри страницы списка продуктов jsp? –

+0

создать продукт: 'Продукт p = new Product()', установить значения продукта. Затем создайте категорию: 'Category c = new Category()', установите значения категории и добавьте товар 'p' в эту категорию:' c.addProduct (p) '. Затем передайте метод 'c' в' session.save (c) '. это сохранит категорию 'c' вместе с продуктом' p'. –

Смежные вопросы