Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is it possible to return a partially loaded entity attached to the persistence context when using projections? #1957

Open
voronovmaksim opened this issue Nov 20, 2024 · 1 comment
Labels

Comments

@voronovmaksim
Copy link

voronovmaksim commented Nov 20, 2024

Hi,

Thank you for this amazing library!

I have a question about attaching entities to the persistence context when using projections. Below is an example of what I’m trying to achieve:

@AllArgsConstructor
@NoArgsConstructor
public abstract class AbstractBaseRepository<TEntity extends Product, TId> {
    @Inject
    BlazeCriteriaBuilderFactory cbf;

    Class<TEntity> entityClass;

    public TEntity attached(TId id) {
        // This works as expected since the entity is attached to the persistence context.
        TEntity product = cbf.create(entityClass)
                .from(entityClass)
                .where("id").eq(id)
                .getSingleResult();

        product.setName("changed name"); // Changes will be committed to the DB at the end of the transaction.
        return product;
    }

    public TEntity notAttached(TId id) {
        // Using an ObjectBuilder, the entity is not attached to the persistence context.
        TEntity product = cbf.create(Tuple.class)
                .from(entityClass)
                .selectNew(new ObjectBuilder<TEntity>() {

                    @Override
                    public <X extends SelectBuilder<X>> void applySelects(X queryBuilder) {
                        queryBuilder
                                .select("id")
                                .select("name");
                    }

                    @Override
                    public TEntity build(Object[] tuple) {
                        Product prd = new Product();
                        prd.setId((String) tuple[0]);
                        prd.setName((String) tuple[1]);
                        return (TEntity) prd;
                    }

                    @Override
                    public List<TEntity> buildList(List<TEntity> list) {
                        return list;
                    }
                })
                .where("id").eq(id)
                .getSingleResult();

        product.setName("changed name"); // Changes will NOT be committed because the entity is detached.
        return product;
    }
}

The attached method works as expected because it directly fetches an entity attached to the persistence context. However, when using projections (e.g., in the notAttached method), the result is not attached since it is created using a custom ObjectBuilder.

What I Want to Achieve

I would like to return an entity when using projections while keeping it attached to the persistence context. Ideally, this entity should have null values for any fields that are not selected. Here's an example of what I need:

TEntity product = cbf.create(entityClass)
        .from(entityClass)
        .select("id")
        .select("name")
        .select("category.name")
        .where("id").eq(id)
        .getSingleResult();

The response would look like this:

{
    "id": 123,
    "name": "changed name",
    "someOtherField": null,
    "category": {
        "name": "categoryName",
        "someOtherField": null
    }
}

category is ManyToOne relation in separate table product_category_product but not jsonB. ManyToMany also is used.

Now it is failed because Object[] is returned but not TEntity.

My Questions

  1. Is there a way to achieve this behavior (returning an attached entity with partially loaded fields) out of the box without using an ObjectBuilder?
  2. If not, is this limitation due to design? Am i right?
  3. Are there any best practices or workarounds to accomplish this use case?

Any insights or suggestions would be greatly appreciated. Thanks in advance for your help!

FYI

I intentionally use TEntity to keep AbstractBaseRepository generic and applicable to any entity type.

@beikov
Copy link
Member

beikov commented Nov 27, 2024

Is there a way to achieve this behavior (returning an attached entity with partially loaded fields) out of the box without using an ObjectBuilder?

Not with Blaze-Persistence. You can use Hibernate ORM bytecode enhancement and lazy groups to achieve this if you want.

If not, is this limitation due to design? Am i right?

Blaze-Persistence can only do what Hibernate ORM allows, and partially loaded entities simply requires the use of bytecode enhancement with lazy groups, so there is nothing Blaze-Persistence can do.

Are there any best practices or workarounds to accomplish this use case?

The way Blaze-Persistence envisions such use cases is to use updatable entity views.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants