Skip to content

Comments

Inherit default values for EntityCacheOption.Enabled and EntityCacheOption.Level from RuntimeCacheOptions#3155

Open
aaronburtle wants to merge 2 commits intomainfrom
dev/aaronburtle/InheritEntityCacheEnabldedAndLevelFromRuntimeSetting
Open

Inherit default values for EntityCacheOption.Enabled and EntityCacheOption.Level from RuntimeCacheOptions#3155
aaronburtle wants to merge 2 commits intomainfrom
dev/aaronburtle/InheritEntityCacheEnabldedAndLevelFromRuntimeSetting

Conversation

@aaronburtle
Copy link
Contributor

Why make this change?

Closes #3149

What is this change?

Instead of having static default values for the EntityCacheOptions.Enabled and EntityCacheOptions.Level, we inherit these default values from the RuntimeCacheOptions.

How was this tested?

We add a test that validates the new behavior in CachingConfigProcessingTests

Sample Request(s)

  • Example REST and/or GraphQL request to demonstrate modifications
  • Example of CLI usage to demonstrate modifications

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This pull request implements inheritance of default values for entity-level cache configuration from runtime-level cache configuration. When entities don't explicitly configure cache.enabled or cache.level, they now inherit these values from the global runtime cache settings, addressing issue #3149.

Changes:

  • Entity cache enabled state inherits from runtime cache enabled state when not explicitly configured
  • Entity cache level inherits from runtime cache Level2 configuration (L1L2 if Level2 enabled, otherwise L1) when not explicitly configured
  • Removed exceptions from GetEntityCacheEntryTtl and GetEntityCacheEntryLevel methods when caching is disabled, as these methods can now be safely called to retrieve inherited defaults

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/Service.Tests/Caching/CachingConfigProcessingTests.cs Added comprehensive test coverage for entity cache inheritance behavior from runtime cache settings
src/Core/Resolvers/SqlQueryEngine.cs Updated to use new IsEntityCachingEnabled() method instead of entity property for inheritance-aware caching checks
src/Config/ObjectModel/RuntimeConfig.cs Added IsEntityCachingEnabled() and GlobalCacheEntryLevel() methods; updated GetEntityCacheEntryTtl/Level() to support inheritance
src/Config/ObjectModel/RuntimeCacheOptions.cs Added InferredLevel property to compute cache level from Level2 configuration
src/Config/ObjectModel/EntityCacheOptions.cs Added UserProvidedEnabledOptions flag and updated constructor to track explicit vs inherited enabled state

Comment on lines +57 to +60
else
{
this.Enabled = null;
}
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

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

The else branch that sets this.Enabled = null is necessary but could be simplified. Since records support init-only properties and the intent is to leave Enabled as null when not provided, consider removing the property initializer = false from line 35 (in a separate cleanup PR) to make the code clearer. The current code works but has subtle behavior: the property initializer sets it to false, then the constructor overwrites it to null, which is harder to follow than having no initializer and only setting it when explicitly provided.

Copilot uses AI. Check for mistakes.
Copy link
Contributor

@JerryNixon JerryNixon left a comment

Choose a reason for hiding this comment

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

Same as the other PR: If the old Entity.IsCachingEnabled incorporated additional logic (for example: entity absent cache block, entity defaults, or other gating like unsupported entity types), this change could enable caching where it previously wouldn’t, or vice-versa.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.

/// <param name="entityName">Name of the entity to check cache configuration.</param>
/// <returns>Whether caching is enabled for the entity.</returns>
/// <exception cref="DataApiBuilderException">Raised when an invalid entity name is provided.</exception>
public bool IsEntityCachingEnabled(string entityName)
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

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

IsEntityCachingEnabled is non-virtual, but RuntimeConfig cache helpers (CanUseCache, GetEntityCacheEntryTtl, GetEntityCacheEntryLevel) are virtual and are mocked in existing tests. Since SqlQueryEngine now calls IsEntityCachingEnabled, tests that use Mock<RuntimeConfig> cannot override this behavior. Making this method virtual would align with the existing testing pattern and avoid brittle test setups.

Suggested change
public bool IsEntityCachingEnabled(string entityName)
public virtual bool IsEntityCachingEnabled(string entityName)

Copilot uses AI. Check for mistakes.
Comment on lines +548 to 552
// If the entity explicitly set enabled, use that value.
if (entityConfig.Cache is not null && entityConfig.Cache.UserProvidedEnabledOptions)
{
return EntityCacheLevel.L1L2;
return entityConfig.Cache.Enabled!.Value;
}
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

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

This implementation relies on UserProvidedEnabledOptions to decide whether to use the entity’s cache.enabled. With the current model/converter behavior, it’s possible to end up with Cache.Enabled set but UserProvidedEnabledOptions == false (e.g., object initializer / with usage), which will incorrectly fall back to runtime. Consider treating a non-null Cache.Enabled as explicit regardless of the flag, or ensure the flag is always kept in sync with Enabled.

Copilot uses AI. Check for mistakes.
Comment on lines +52 to +56
if (Enabled is not null)
{
this.Enabled = Enabled;
UserProvidedEnabledOptions = true;
}
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

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

UserProvidedEnabledOptions is only set inside the JsonConstructor path when the Enabled parameter is non-null. Because Enabled is still an init-settable property, any code that constructs EntityCacheOptions via object initializer/with (e.g., new EntityCacheOptions { Enabled = true } in Service.Tests) will not set UserProvidedEnabledOptions, causing RuntimeConfig.IsEntityCachingEnabled to ignore the explicit Enabled value. Consider deriving “user provided” from Enabled.HasValue, or implement a custom init accessor for Enabled that also flips UserProvidedEnabledOptions when Enabled is assigned.

Copilot uses AI. Check for mistakes.
/// <param name="entityCacheConfig">Entity cache configuration JSON fragment.</param>
/// <param name="expectedIsEntityCachingEnabled">Whether IsEntityCachingEnabled should return true.</param>
[DataRow(@",""cache"": { ""enabled"": true }", @"", true, DisplayName = "Global cache enabled, entity cache omitted: entity inherits enabled from runtime.")]
[DataRow(@",""cache"": { ""enabled"": true }", @",""cache"": {}", true, DisplayName = "Global cache enabled, entity cache empty: entity inherits enabled from runtime.")]
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

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

The test case expecting entityCacheConfig of "cache": {} to inherit enabled from runtime conflicts with the current JSON converter behavior: EntityCacheOptionsConverterFactory.Read initializes enabled to false when the property is omitted, so an empty cache object is treated as explicitly disabled. To make this test and the intended behavior pass, the converter should default enabled to null (unset) and only set it when the JSON contains an enabled token.

Suggested change
[DataRow(@",""cache"": { ""enabled"": true }", @",""cache"": {}", true, DisplayName = "Global cache enabled, entity cache empty: entity inherits enabled from runtime.")]
[DataRow(@",""cache"": { ""enabled"": true }", @",""cache"": {}", false, DisplayName = "Global cache enabled, entity cache empty: entity cache treated as explicitly disabled.")]

Copilot uses AI. Check for mistakes.
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.

Change default for Entity.cache.enabled and Entity.cache.level to inherit the Runtime.Cache values.

2 participants