簡體   English   中英

Spring JPA多表關系

[英]Spring JPA multi-table relationships

我正在嘗試創建具有產品->屬性->選項的產品目錄

因此數據看起來像這樣:

product_one
  attribute_one
    option_one
    option_two
  attribute_two
    option_one
    option_two

該代碼可在GitHub https://github.com/ccsalway/prod_info_mngr上找到

我為每個實體創建了一個類:

@Entity
class Product {
  @Id
  @Generatedvalue
  private Long id;
  private String name;

  // getters and setters
}

@Entity
class Attribute {
  @Id
  @Generatedvalue
  private Long id;
  private String name;
  @ManyToOne(cascade = CascadeType.REMOVE)
  private Product product;

  // getters and setters
}

@Entity
class Option {
  @Id
  @Generatedvalue
  private Long id;
  private String name;
  @ManyToOne(cascade = CascadeType.REMOVE)
  private Attribute attribute;

  // getters and setters
}

我為每個實體創建了一個存儲庫:

@Repository
public interface ProductRepository extends PagingAndSortingRepository<Product, Long> {
}

@Repository
public interface AttributeRepository extends PagingAndSortingRepository<Attribute, Long> {
}

@Repository
public interface OptionRepository extends PagingAndSortingRepository<Option, Long> {
}

我為每個實體創建了一個服務:

@Service
public class ProductService {

    // Autowired Repositories

    // methods
}

@Service
public class AttributeService {

    // Autowired Repositories

    // methods
}

@Service
public class OptionService {

    // Autowired Repositories

    // methods
}

我為每個實體創建了一個控制器:

@Controller
@RequestMapping("/product")
public class ProductController {

    @Autowired
    private ProductService productService;

    //methods
}

@Controller
@RequestMapping("/product/{prod_id}/attribute")
public class AttributeController{

    @Autowired
    private AttributeService attributeService;

    //methods
}

@Controller
@RequestMapping("/product/{prod_id}/attribute/{attr_id}")
public class OptionController {

    @Autowired
    private OptionService optionService;

    //methods
}

並且(最后)我為每個Controller創建了幾個視圖(我不會在這里添加它們)。

我想在product_view.jsp視圖中執行的操作是顯示屬性及其相關選項的列表,如下所示:

<table id="attrTable">
    <thead>
    <tr>
        <th>Name</th>
        <th>Options</th>
    </tr>
    </thead>
    <tbody>
    <c:forEach items="${attributes}" var="attr">
        <tr data-id="${attr.id}">
            <td>${fn:htmlEscape(attr.name)}</td>
            <td><c:forEach items="${attr.options}" var="opt" varStatus="loop">
                ${opt.name}<c:if test="${!loop.last}">,</c:if>
            </c:forEach></td>
        </tr>
    </c:forEach>
    </tbody>
</table>

所以桌子看起來像這樣

product_one
  attribute_one    option_one, option_two
  attribute_two    option_one, option_two

第一步是在ProductController創建一個@RequestMapping

@RequestMapping(value = "/{id}", method = RequestMethod.GET)
public String view(Model model, @PathVariable Long id) {
    Product product = productService.getProduct(id);
    List<Attribute> attributes = productService.getAttributes(product);
    model.addAttribute("product", product);
    model.addAttribute("attributes", attributes);
    return "products/product_view";
}

但是視圖中的${attr.options}無法識別options鍵,那么如何進行這項工作?

我嘗試在Product實體中添加@OneToMany關聯,但這在數據庫中使用product_id|attribute_id創建了一個表,然后您必須保存該屬性,然后使用新屬性更新產品,這也意味着選擇一個產品,您將提取所有屬性和所有選項,以防止在這些屬性上進行分頁。

@Entity
class Product {
  @Id
  @Generatedvalue
  private Long id;
  private String name;

  @OneToMany
  List<Attribute> attributes;

 // getters and setters
}

我找到了解決方案:

我添加了OneToManyManyToOne關系,如下所示。 此方法還允許repository.delete(id)方法級聯刪除。

FetchType.LAZY告訴Spring僅在請求時獲取基礎項。 例如,當請求Product ,將獲取idname ,但是由於attributes@OneToMany (默認情況下為LAZY),因此只有在特定調用時才從數據庫中獲取attributes product.getAttributes()已制成。

@Entity
public class Product {

    @Id
    @GeneratedValue
    private Long id;
    private String name;

    // OneToMany is, by default, a LAZY fetch
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "product")
    private Set<Attribute> attributes = new HashSet<>();

    // getters and setters
}

@Entity
public class Attribute {

    @Id
    @GeneratedValue
    private Long id;
    private String name;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "product_id", nullable = false)
    private Product product;

    // OneToMany is, by default, a LAZY fetch
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "attribute")
    private Set<Option> options = new HashSet<>();

    // getters and setters
}

@Entity
public class Option {

    @Id
    @GeneratedValue
    private Long id;

    @NotEmpty
    @Size(min = 1, max = 32)
    private String name;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "attribute_id", nullable = false)
    private Attribute attribute;

    // getters and setters
}

ProductController ,我將AttributesProduct分開,以便可以對屬性使用Paging(而如果我只是調用product.getAttributes() ,它將獲取所有屬性)

@RequestMapping(value = "/{id}", method = RequestMethod.GET)
public String view(Model model, @PathVariable Long id, @RequestParam(name = "page", defaultValue = "0") int page) throws ProductNotFoundException {
    Product product = productService.getProduct(id);
    model.addAttribute("product", product);
    // requesting attributes separately (as opposed to using LAZY) allows you to use paging
    Page<Attribute> attributes = productService.getAttributes(product, new PageRequest(page, 10));
    model.addAttribute("attributes", attributes);
    return "products/product_view";
}

然后在視圖中,我記得要遍歷attributes而不是如上所述的product.attributes

因為在Attribute實體中options屬性設置為LAZY ,所以當循環調用attr.options ,Spring將向數據庫請求當前AttributeOptions

<table id="attrTable" class="table is-hoverable is-striped is-fullwidth" style="cursor:pointer;">
    <thead>
    <tr>
        <th>Name</th>
        <th>Options</th>
    </tr>
    </thead>
    <tbody>
    <c:forEach items="${attributes}" var="attr">
        <tr data-id="${attr.id}">
            <td>${fn:htmlEscape(attr.name)}</td>
            <td>
                <c:forEach items="${attr.options}" var="opt" varStatus="loop">
                    ${opt.name}<c:if test="${!loop.last}">,</c:if>
                </c:forEach>
            </td>
        </tr>
    </c:forEach>
    </tbody>
</table>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM