当前位置: 首页 > 面试题库 >

带有复合主键的Spring数据表

冀崇凛
2023-03-14
问题内容

我使用spring数据休息作为基础。但是当实体具有复合主键时,我不知道如何通过提供主键来获得实体。

河类:

@Entity
public class River {
    private RiverPK id;
    private Double length;
    private Timestamp date;
    private String comment;


    @Basic
    @Column(name = "length")
    public Double getLength() {
        return length;
    }

    public void setLength(Double length) {
        this.length = length;
    }

    @Basic
    @Column(name = "date")
    public Timestamp getDate() {
        return date;
    }

    public void setDate(Timestamp date) {
        this.date = date;
    }

    @Basic
    @Column(name = "comment")
    public String getComment() {
        return comment;
    }

    public void setComment(String comment) {
        this.comment = comment;
    }

    @Id
    public RiverPK getId() {
        return id;
    }

    public void setId(RiverPK id) {
        this.id = id;
    }
}

RiverPK课程:

@Embeddable
public class RiverPK implements Serializable {
    private String name;
    private int upcode;
    private int downcode;

    @Column(name = "name")
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Column(name = "upcode")
    public int getUpcode() {
        return upcode;
    }

    public void setUpcode(int upcode) {
        this.upcode = upcode;
    }

    @Column(name = "downcode")
    public int getDowncode() {
        return downcode;
    }

    public void setDowncode(int downcode) {
        this.downcode = downcode;
    }

}

RiverDAO类:

@RepositoryRestResource(path = "river")
public interface RiverDAO extends JpaRepository<River, RiverPK> {
}

然后,我可以通过调用get http:// localhost:8080 / river
/
获取河流数据,还可以通过调用post http:// localhost:8080 /
river /
{river json} 为db创建新实体

河json是:

id": {

    "name": "1",
    "upcode": 2,
    "downcode": 3

},
"length": 4.4,
"date": 1493740800000,
"comment": "6"
}

在spring data rest doc中,它应该能够调用get localhost:8080 / river /
1(主键)来获取主键为1的实体。这在实体只有一个主键时可以使用。但是我的实体河具有复合主键,如RiverPK。如果我调用get localhost:8080
/ river / {name =‘1’,upcode = 2,downcode =
3},它将返回错误“找不到能够从[java.lang.String]类型转换为[com]类型的转换器.example.db.entity.RiverPK]“,我的意思是spring使用{name
=‘1’,upcode = 2,downcode = 3}作为字符串,但不使用RiverPK类型。

问题是如何将复合主键作为其他普通实体调用get \ put \ delete?


问题答案:

从为具有复合ID的实体定制HATEOAS链接生成中学习后,我发现了一个更为通用的解决方案。

首先,创建一个SpringUtil以从Spring获取bean。

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class SpringUtil implements ApplicationContextAware {
    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if(SpringUtil.applicationContext == null) {
            SpringUtil.applicationContext = applicationContext;
        }
    }

    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    public static Object getBean(String name){
        return getApplicationContext().getBean(name);
    }

    public static <T> T getBean(Class<T> clazz){
        return getApplicationContext().getBean(clazz);
    }

    public static <T> T getBean(String name,Class<T> clazz){
        return getApplicationContext().getBean(name, clazz);
    }
}

然后,实现BackendIdConverter。

import com.alibaba.fastjson.JSON;
import com.example.SpringUtil;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.webmvc.spi.BackendIdConverter;
import org.springframework.stereotype.Component;

import javax.persistence.EmbeddedId;
import javax.persistence.Id;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.net.URLDecoder;
import java.net.URLEncoder;

@Component
public class CustomBackendIdConverter implements BackendIdConverter {

    @Override
    public boolean supports(Class<?> delimiter) {
        return true;
    }

    @Override
    public Serializable fromRequestId(String id, Class<?> entityType) {
        if (id == null) {
            return null;
        }

        //first decode url string
        if (!id.contains(" ") && id.toUpperCase().contains("%7B")) {
            try {
                id = URLDecoder.decode(id, "UTF-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }

        //deserialize json string to ID object
        Object idObject = null;
        for (Method method : entityType.getDeclaredMethods()) {
            if (method.isAnnotationPresent(Id.class) || method.isAnnotationPresent(EmbeddedId.class)) {
                idObject = JSON.parseObject(id, method.getGenericReturnType());
                break;
            }
        }

        //get dao class from spring
        Object daoClass = null;
        try {
            daoClass = SpringUtil.getBean(Class.forName("com.example.db.dao." + entityType.getSimpleName() + "DAO"));
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        //get the entity with given primary key
        JpaRepository simpleJpaRepository = (JpaRepository) daoClass;
        Object entity = simpleJpaRepository.findOne((Serializable) idObject);
        return (Serializable) entity;

    }

    @Override
    public String toRequestId(Serializable id, Class<?> entityType) {
        if (id == null) {
            return null;
        }

        String jsonString = JSON.toJSONString(id);

        String encodedString = "";
        try {
            encodedString = URLEncoder.encode(jsonString, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return encodedString;
    }
}

之后。你可以做你想做的。

下面有一个示例。

  • 如果实体具有单个属性pk,则可以正常使用localhost:8080 / demo / 1。根据我的代码,假设pk具有注释“ @Id”。
  • 如果实体由pk组成,假设pk是demoId类型,并且具有注释“ @EmbeddedId”,则可以使用localhost:8080 / demo / {demoId json}进行获取/放置/删除。并且您的自我链接将是相同的。


 类似资料:
  • 我使用spring数据rest作为CRUD。但是当实体具有复合主键时,我不知道如何通过给出主键来获得一个实体。 河流等级: RiverPK类: Riverdoo级: 然后我可以通过调用get http://localhost:8080/river/获取河流数据,还可以通过调用post http://localhost:8080/river/{river json}为db创建新的实体 river j

  • 我在使用复合主键创建实体时遇到问题,该键也是外键。这是我的表和关系表原理图。当我想创建新闻实体时,我收到了带有null creatingnews的错误消息。新闻翻译有复合主键,外键引用到新闻表。 这是我的代码: 新闻聚合 新闻翻译 标签 新闻语言ID 在NewsFactory中,我希望使用NewsTranslation创建NewsAggregate,但有错误消息NullPointer。 新闻工厂

  • 我使用Spring Data、JPA和Hibernate作为持久性提供程序进行了以下设置。我的所有实体都继承自基类 例如:

  • 我有一个实体,其复合主键定义为 和实体 我们有一个前端应用程序发送以下请求 它在调用pageable with sort参数之后: 失败,使用 PropertyReferenceException:未找到类型Entity的属性theNum! 通过发送正确的请求(如: 最后,我的问题是--有没有一种方法可以告诉spring将收到的“thenum”排序参数正确地作为复合主键的一部分来处理? 或者我应该

  • 看起来Spring数据r2dbc不支持复合主键。这是已知的问题吗? 我看不到对@Embedded的支持。

  • 问题内容: 我正在设计一个数据库,该数据库将用于存储来自许多不同来源的数据。我存储的实例由原始来源分配了唯一的ID。我存储的每个实例都应包含有关其来源的信息,以及与此来源相关联的ID。 作为示例,请考虑说明该问题的下表: 请注意,尽管每个来源的唯一,但有可能在不同来源中找到相同的来源。 我对关系数据库有一个不错的了解,但是与专家甚至是经验丰富的用户都相去甚远。我在此设计中面临的问题是应该用作主键。