在spring数据jpa投影中使用嵌入值对象

时间:2018-02-27 13:50:03

标签: java spring-data-jpa

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

我们说我有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而不是使用String来表示name实体中的Product属性,我想使用一个名为Name的值对象:< / p>

@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

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

1 个答案:

答案 0 :(得分:1)

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

interface ProductSummary {
    NameSummary getName();

    interface NameSummary {
      String getValue();
    }
}

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

非常清楚地记录here

并确保您的界面和方法是公开的。