【问题标题】:Using embedded value objects in spring data jpa projections在 Spring Data JPA 投影中使用嵌入的值对象
【发布时间】:2018-08-07 04:41:12
【问题描述】:

我正在使用 Spring Boot 2.0RC2,在我阅读的文档中,您可以在调用存储库时返回实体的投影而不是整个实体。如果我在我的实体中使用字符串,但当我使用嵌入的值对象时,这可以正常工作。

假设我有Product 实体:

@Entity
@Table(name = "t_product")
public class Product extends BaseEntity {

    @Column(nullable = false)
    private String name;

    private Product() {}

    private Product(final String name) {
        this.name = name;
    }

    public static Result<Product> create(@NonNull final String name) {
        return Result.ok(new Product(name));
    }

    public String getName() {
        return name;
    }

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

BaseEntity 只包含idcreatedupdated 属性。

我的投影界面名为ProductSummary

interface ProductSummary {
    String getName();
    Long getNameLength();
}

在我的ProductRepository 中,我有以下方法返回ProductSummary

public interface ProductRepository extends JpaRepository<Product, Long> {
    @Query(value = "SELECT p.name as name, LENGTH(p.name) as nameLength FROM Product p WHERE p.id = :id")
    ProductSummary findSummaryById(@Param("id") Long id);
}

这工作得很好。现在假设我正在做 DDD,而不是使用字符串来表示 Product 实体中的 name 属性,我想使用一个名为 Name 的值对象:

@Embeddable
public class Name implements Serializable {

    public static final int MAX_NAME_LENGTH = 100;

    @Column(nullable = false, length = Name.MAX_NAME_LENGTH)
    private String value;

    private Name() {}

    private Name(final String value) {
        this.value = value;
    }

    public static Result<Name> create(@NonNull final String name) {
        if (name.isEmpty()) {
            return Result.fail("Name cannot be empty");
        }

        if (name.length() > MAX_NAME_LENGTH) {
            return Result.fail("Name cannot be longer than " + MAX_NAME_LENGTH + " characters");
        }

        return Result.ok(new Name(name));
    }

    public String getValue() {
        return value;
    }
}

我将我的 Product 实体更改为:

@Entity
@Table(name = "t_product")
public class Product extends BaseEntity {

    @Embedded
    private Name name;

    private Product() {}

    private Product(final Name name) {
        this.name = name;
    }

    public static Result<Product> create(@NonNull final Name name) {
        return Result.ok(new Product(name));
    }

    public Name getName() {
        return name;
    }

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

ProductSummary 中,我将返回类型从String 更改为Name

当我运行时,我总是得到异常:

Caused by: java.lang.IllegalAccessError: tried to access class com.acme.core.product.ProductSummary from class com.sun.proxy.$Proxy112

我可以完成这项工作还是我错过了一些不允许这样做的限制?

【问题讨论】:

    标签: java spring-data-jpa


    【解决方案1】:

    如果您希望获得完整的 Name 字段(不是 Name 类中的特定字段),那么您需要创建另一个接口,例如 ProductSummary。

    interface ProductSummary {
        NameSummary getName();
    
        interface NameSummary {
          String getValue();
        }
    }
    

    无需更改存储库中的任何内容。

    here 记录得很清楚

    并确保您的接口和方法是公开的。

    【讨论】:

    • 我确实试过了,但还是没有骰子,这和我使用自定义查询有什么关系吗?
    • 与自定义查询无关,接口中的返回类型和方法名是否设置正确?
    • 据我所知,我拿走了你的代码,删除了 String getName() 并留下了 NameSummary getName() 并添加了新界面。其余代码与我在上面发布的完全相同。当我使用 String 类型作为名称时,一切正常,当我将类型迁移到 Name 时,它给了我异常(即使添加了 NameSummary
    • 同样的异常?
    • 是的,不幸的是同样的例外
    猜你喜欢
    • 2019-02-17
    • 1970-01-01
    • 1970-01-01
    • 2015-02-05
    • 2020-01-10
    • 1970-01-01
    • 2022-12-02
    • 2020-06-23
    • 2021-06-01
    相关资源
    最近更新 更多