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

[ODS-5665] FOR PRELIMINARY REVIEW #1156

Closed
wants to merge 4 commits into from
Closed

[ODS-5665] FOR PRELIMINARY REVIEW #1156

wants to merge 4 commits into from

Conversation

gmcelhanon
Copy link
Contributor

No description provided.


public static EntityProperty FindIdentificationCodeProperty(Entity entity)
{
var entityFullName = entity.FullName.Name;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably just use entity.FullName here because it is a struct and includes the schema. Dropping the schema delineation could be problematic due to the possibility of a "homograph" (an extension with a resource of the same name).

using EdFi.Ods.Common.Specifications;

namespace EdFi.Ods.Common.Providers.Criteria;

internal static class AggregateRootCriteriaProviderHelpers
{
private static string[] _uniqueIds;
private static readonly ConcurrentDictionary<string, EntityProperty> _entityIdentificationCodePropertyCache = [];
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename this to _identificationCodePropertyByRootEntityName. This makes it clear what the dictionary is keyed by.

public static EntityProperty FindIdentificationCodeProperty(Entity entity)
{
var entityFullName = entity.FullName.Name;
var identificationCodeEntityProperty = _entityIdentificationCodePropertyCache.GetValueOrDefault(entityFullName);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should use the GetOrAdd mehtod of ConcurrentDictionary and go ahead and store the null value if no identification code is found to avoid doing this logic for a particular entity more than once. We definitely don't want to be repeatedly looking through the model for the same entity time and time again.


EntityProperty FindIdentificationCodePropertyInAssociations(Entity entity)
{
return entity.OutgoingAssociations
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'll want to use NavigableChildren for this... only search within the resource/aggregate. OutgoingAssociations includes all outbound associations, even FKs to other resources.

: "r";

var identificationCodeTableJoin = CreateIdentificationCodeTableJoin(entityIdentificationCodeProperty, alias);
queryBuilder.Join(identificationCodeTableJoin.TableName, _ => identificationCodeTableJoin, JoinType.LeftOuterJoin);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would think you would want to use an INNER JOIN here, and only activate this logic if there are actually parameters supplied that match a search for the identification code on this particular entity.

In other words, just because there's an identification code defined for the entity/resource being requested doesn't mean we want to introduce any joins to the identification code child table, and certainly not a left join which is more expensive. We only want to perform a join if they are providing identification code-related parameters and then the join should be an inner join.

So, in the other function, once you've identified there's an IdentificationCode property on a child table, you should go ahead and create a dictionary of entity properties keyed by the corresponding parameter names for that child entity. (After writing this comment, I see that you've basically got that function written already at the bottom of this class. It just needs to be refined a bit and reusable by the Open API metadata generation process.)

Also, remember to store this dictionary (or a null value if there's no identification codes to be found for it) in the top level ConcurrentDictionary in the applicator class (keyed by the Entity.FullName). This will allow you to quickly determine first if there is any identification codes for the entity without doing the work each time, and then second, if there are any matching parameters supplied in the incoming additionalParameter parameter (dictionary). Only if both of those conditons are met would you proceed to building the INNER JOIN to the identification code table.

public void ApplyAdditionalParameters(QueryBuilder queryBuilder, Entity entity, AggregateRootWithCompositeKey specification,
IDictionary<string, string> additionalParameters)
{
if (additionalParameters == null || !additionalParameters.Any() || additionalParameters.All(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you could leave the null and the Any checks, but I don't think the latter is needed because ASP.NET will fill that dictionary with values that were not bindable to the other models in the controller signature. We should confirm this, but I think this will be wasted worked. Thoughts/concerns?


return null;

EntityProperty FindIdentificationCodePropertyInAssociations(Entity entity)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method name is misleading because you're looking for a property in the child table, not the association (aka FK). The identification code will never be part of any association. So if we were leaving this as-is (but I recommend changes to what this is returning below), I would say call this "TryFindIdentificationCodeProperty" and change the semantics (return a bool for success/failure, and an out property). But... read on.

bool IsQueryableIdentificationCodeProperty(EntityProperty property)
{
return property.PropertyName.Equals("IdentificationCode") ||
!(property.IsFromParent || property.IsAlreadyDefinedInCSharpEntityBaseClasses());
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IsAlreadyDefinedInCSharpEntityBaseClasses is currently unused by the API project and probably should only be available for use by CodeGen. It looks like IsPredefinedProperty is in use and accomplishes the same thing. Let's use that.

}
}

private IDictionary<string, EntityProperty> GetIdentificationCodeParameters(EntityProperty entityIdentificationCodeProperty)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do this work once per entity, and cache it by the root entity name in the top-level ConcurrentDictionary.

@mjaksn mjaksn closed this Oct 11, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants