首页 > 解决方案 > JPA mappedBy 引用了一个未知的目标实体

问题描述

我正在编写一个简单的库存数据库,其中包含产品、订单和客户表。数据库定义可以在这里找到:

CREATE TABLE public.customers
(
    id integer NOT NULL DEFAULT nextval('customers_id_seq'::regclass),
    title character varying(10) COLLATE pg_catalog."default" NOT NULL,
    first_name character varying(50) COLLATE pg_catalog."default" NOT NULL,
    middle_names character varying(50) COLLATE pg_catalog."default",
    last_name character varying(50) COLLATE pg_catalog."default" NOT NULL,
    email character varying(50) COLLATE pg_catalog."default" NOT NULL,
    phone_number character varying(50) COLLATE pg_catalog."default" NOT NULL,
    CONSTRAINT customers_pkey PRIMARY KEY (id)
)

CREATE TABLE public.products
(
    id integer NOT NULL DEFAULT nextval('products_id_seq'::regclass),
    name character varying(100) COLLATE pg_catalog."default" NOT NULL,
    sku integer NOT NULL,
    inventory_on_hand integer NOT NULL,
    reorder_threshold integer NOT NULL,
    price numeric(5,2),
    inventory_to_be_shipped integer NOT NULL,
    CONSTRAINT products_pkey PRIMARY KEY (id)
)

CREATE TABLE public.order_items
(
    id integer NOT NULL DEFAULT nextval('order_items_id_seq'::regclass),
    product_id integer NOT NULL,
    order_id integer NOT NULL,
    CONSTRAINT order_items_pkey PRIMARY KEY (id),
    CONSTRAINT order_items_order_id_fkey FOREIGN KEY (order_id)
        REFERENCES public.orders (id) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE NO ACTION,
    CONSTRAINT order_items_product_id_fkey FOREIGN KEY (product_id)
        REFERENCES public.products (id) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE NO ACTION
)

CREATE TABLE public.orders
(
    id integer NOT NULL DEFAULT nextval('orders_id_seq'::regclass),
    customer_id integer,
    order_date date NOT NULL DEFAULT now(),
    arrival_date date,
    CONSTRAINT orders_pkey PRIMARY KEY (id),
    CONSTRAINT orders_customer_id_fkey FOREIGN KEY (customer_id)
        REFERENCES public.customers (id) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE NO ACTION
)

我正在尝试实现一个 Spring Security 资源服务器来对数据库执行 CRUD 操作。我已经为数据库中的每个表实现了实体类,但是当尝试启动服务器时,我得到了一个

org.hibernate.AnnotationException: mappedBy reference an unknown target entity property: edu.finalyearproject.imsresourceserver.models.Order.customers in edu.finalyearproject.imsresourceserver.models.Customer.orders

我的实体和存储库类可以在下面找到:

产品.java:

@Entity
@Table(name = "products")
@Data
public class Product
{
    @Id
    @GeneratedValue(strategy= GenerationType.IDENTITY)
    private Integer id;
    private String name;
    private Integer sku;
    private Float price;
    private Integer inventory_on_hand;
    private Integer reorder_threshold;

    @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, fetch = FetchType.LAZY)
    @JoinTable(
            name = "order_items",
            joinColumns = @JoinColumn(name = "product_id"),
            inverseJoinColumns = @JoinColumn(name = "order_id")
    )
    private Set<Order> orders = new HashSet<>();
}

客户.java

@Entity
@Table(name = "customers")
@Data
public class Customer
{
    @Id
    @GeneratedValue(strategy= GenerationType.IDENTITY)
    private Integer id;
    private String title;
    private String first_name;
    private String middle_names;
    private String last_name;
    private String email;
    private String phone_number;

    @OneToMany(mappedBy = "customer", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private Set<Order> orders;
}

订单.java

@Entity
@Table(name = "orders")
@Data
public class Order
{
    @Id
    @GeneratedValue(strategy= GenerationType.IDENTITY)
    private Integer id;

    @ManyToOne
    @JoinColumn(name="customer_id", nullable=false)
    private Customer customer;

    private Date order_date;

    private Date arrival_date;

    @ManyToMany(mappedBy = "orders", cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    private Set<Product> products = new HashSet<>();
}

我知道问题与实体之间的关系有关,但我一直无法找到解决方案。任何帮助将不胜感激。

标签: javahibernatejpaspring-securityspring-data-jpa

解决方案


尝试纠正这一点:

@Entity
public class Customer
{
    // ...

    @OneToMany(mappedBy = "orders", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private Set<Order> orders;
}

对此:

@Entity
public class Customer
{
    // ...

    @OneToMany(mappedBy = "customer", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private Set<Order> orders;
}

请参阅文档中的其他说明。

你也应该更正你的Product-Order @ManyToMany协会。只有该关联的一侧应该使用@JoinTable另一侧应该使用注释mappedBy的属性。@ManyToMany像这样的东西:

@Entity
public class Product
{
    // ...

    @ManyToMany(
       cascade = {CascadeType.PERSIST, CascadeType.MERGE},
       fetch = FetchType.LAZY
    )
    @JoinTable(
            name = "order_items",
            joinColumns = @JoinColumn(name = "product_id"),
            inverseJoinColumns = @JoinColumn(name = "order_id")
    )
    private Set<Order> orders = new HashSet<>();
}

@Entity
public class Order
{
    // ...

    @ManyToMany(
       mappedBy = "orders",
       cascade = {CascadeType.PERSIST, CascadeType.MERGE},
       fetch = FetchType.LAZY)
    private Set<Product> products = new HashSet<>();
}

正如文档中所述:

对于@ManyToMany关联,REMOVE级联的实体状态转换没有意义,因为它会传播到链接表之外。由于另一方可能被父方的其他实体引用,因此自动删除可能以ConstraintViolationException.

同样正如文档的本节中所解释的那样:

如果您忘记了JOIN FETCH所有EAGER关联,Hibernate 将为每一个关联发出辅助选择,这反过来又会导致 N+1 查询问题。

因此,您应该更喜欢 LAZY 关联。


推荐阅读