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

Projections on the discriminator property fail #2939

Open
agiannone opened this issue Mar 15, 2024 · 9 comments
Open

Projections on the discriminator property fail #2939

agiannone opened this issue Mar 15, 2024 · 9 comments
Labels

Comments

@agiannone
Copy link

Describe the bug
When creating a projection on a discriminator property, the PathTarget throws a ValidationException because the discriminator is not added to the EntityModel as a PropertyModel.
Note that the same issue will be present on any use of the PathTarget that involves the discriminator and doesn't skip validation.

To Reproduce

  1. Create an Entity with a nested interface that uses the discriminator
  2. Query the Entity and add a projection on the discriminator

Expected behavior
It should be possible to add a projection on the discriminator property.

** Please complete the following information: **

  • Server Version: 5.x
  • Driver Version: 4.11
  • Morphia Version: 2.4.14
@agiannone agiannone added the bug label Mar 15, 2024
@evanchooly
Copy link
Member

What's the use case for doing a projection on the discriminator? Such metadata should be ignored/transparent to your application?

@agiannone
Copy link
Author

agiannone commented Mar 15, 2024

I have an Entity which contains a property that is an interface. When I add a projection on the fields of one of the subtypes of the interface, it doesn't include the discriminatorKey to the projection. As a consequence the InstanceCreatorFactory throws out an error as it's can't find a constructor for the interface because the discriminator is missing.

The Projection class does include the following snippet:

if (isIncluding() && entityAnnotation != null && entityAnnotation.useDiscriminator()) { projection.put(mapper.getConfig().discriminatorKey(), 1); }

But this only gets applied to the main Entity and not it's nested interface.

@evanchooly
Copy link
Member

If you're querying by the interface type, you'll need to enable polymorphic queries.

@agiannone
Copy link
Author

agiannone commented Mar 15, 2024

The parent entity is not an interface, so from what I understood, it wouldn't be considered a polymorphic query.

The query is on the parent entity which is a concrete class, the interface is a property of the entity.

@Entity
public class MyEntity {
  @Id private ObjectId myId;
  @Property private MyInterface prop;
}

@Entity( useDiscriminator = true )
public interface MyInterface {}

@Entity( useDiscriminator = true, discriminator = "mydisc" )
public class MyImpl implements MyInterface {
  @Property private int propA;
   ... more properties
}

The query is on MyEntity and I am adding a projection on the properties in MyImpl e.g. "prop.propA"

In this case the Morphia does not include the discriminatorKey into the projection and so the decoding of the MyInterface property fails.

@evanchooly
Copy link
Member

What does your query look like?

@agiannone
Copy link
Author

I've tried to replicate the query as closely as possible in terms of filters and options used. Obviously not all the fields match above, but I've tried to keep the entity and embedded entity references accurate.

Query<MyEntity> query = datastore.find(MyEntity.class)
    .disableValidation()
    .filter( eq( "propertyA", someValue ) )
    .filter( in( "propertyB", listOfValues ) )
    .filter( gte( "datePropertyA", startDate ) )
    .filter( lte( "datePropertyA", endDate ) )
    .filter( ne( "propertyC", otherValue ) );

FindOptions options = new FindOptions()
    .sort( Sort.descending( "datePropertyA" ) )
    .projection().include( "prop.mydisc", "prop.propA" )
    .skip( 0 )
    .limit( 1 );

query.iterator( options ).toList();

@evanchooly
Copy link
Member

I'm not seeing how/where the discrimininator come in to play. Is the failure you're seeing that the projection doesn't know how to "see past" the interface definition?

@agiannone
Copy link
Author

agiannone commented Mar 17, 2024

If I include the discriminator in the projection, then the PathTarget throws a ValidationException due to an invalid path.

If I don't include the discriminator in that projection, then the InstanceCreatorFactory throws a MappingException with the error "No suitable constructor found for type".

@evanchooly
Copy link
Member

If you could put together a reproducer I can take a deeper look. I have some ideas about what might be happening here but I can't quite follow your examples here well enough to be confident in recreating your scenario.

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