diff --git a/src/Core/Services/MetadataProviders/MsSqlMetadataProvider.cs b/src/Core/Services/MetadataProviders/MsSqlMetadataProvider.cs
index 23d12ec31f..1f16c81e28 100644
--- a/src/Core/Services/MetadataProviders/MsSqlMetadataProvider.cs
+++ b/src/Core/Services/MetadataProviders/MsSqlMetadataProvider.cs
@@ -337,7 +337,7 @@ protected override async Task GenerateAutoentitiesIntoEntities(IReadOnlyDictiona
// Currently the source type is always Table for auto-generated entities from database objects.
Entity generatedEntity = new(
Source: new EntitySource(
- Object: objectName,
+ Object: $"{schemaName}.{objectName}",
Type: EntitySourceType.Table,
Parameters: null,
KeyFields: null),
diff --git a/src/Service.Tests/Configuration/ConfigurationTests.cs b/src/Service.Tests/Configuration/ConfigurationTests.cs
index b6607391b7..be2dcca84f 100644
--- a/src/Service.Tests/Configuration/ConfigurationTests.cs
+++ b/src/Service.Tests/Configuration/ConfigurationTests.cs
@@ -5484,10 +5484,10 @@ public async Task TestGraphQLIntrospectionQueriesAreNotImpactedByDepthLimit()
}
///
- ///
+ /// Ensures that autoentities are properly generated into in-memory entities
///
- ///
- ///
+ /// Boolean that indicates if we should also use regular entities from config
+ /// The expected number of entities
///
[TestCategory(TestCategory.MSSQL)]
[DataTestMethod]
@@ -5636,13 +5636,123 @@ public async Task TestAutoentitiesAreGeneratedIntoEntities(bool useEntities, int
}
///
- ///
+ /// Ensures that autoentities are properly generated into in-memory entities when entities have non-default schemas.
///
- ///
- ///
- ///
- ///
- ///
+ /// The pattern to include for autoentities
+ /// Boolean that indicates if the pattern is for the foo schema
+ ///
+ [TestCategory(TestCategory.MSSQL)]
+ [DataTestMethod]
+ [DataRow("foo.%", true, DisplayName = "Test Autoentities with foo schema")]
+ [DataRow("bar.%", false, DisplayName = "Test Autoentities with bar schema")]
+ public async Task TestAutoentitiesGeneratedWithDifferentSchemas(string includePattern, bool isPatternFoo)
+ {
+ // Arrange
+ Dictionary autoentityMap = new()
+ {
+ {
+ "PublisherAutoEntity", new Autoentity(
+ Patterns: new AutoentityPatterns(
+ Include: new[] { includePattern },
+ Exclude: null,
+ Name: null
+ ),
+ Template: new AutoentityTemplate(
+ Rest: new EntityRestOptions(Enabled: true),
+ GraphQL: new EntityGraphQLOptions(
+ Singular: string.Empty,
+ Plural: string.Empty,
+ Enabled: true
+ ),
+ Health: null,
+ Cache: null
+ ),
+ Permissions: new[] { GetMinimalPermissionConfig(AuthorizationResolver.ROLE_ANONYMOUS) }
+ )
+ }
+ };
+
+ // Create DataSource for MSSQL connection
+ DataSource dataSource = new(DatabaseType.MSSQL,
+ GetConnectionStringFromEnvironmentConfig(environment: TestCategory.MSSQL), Options: null);
+
+ // Build complete runtime configuration with autoentities
+ RuntimeConfig configuration = new(
+ Schema: "TestAutoentitiesSchema",
+ DataSource: dataSource,
+ Runtime: new(
+ Rest: new(Enabled: true),
+ GraphQL: new(Enabled: true),
+ Mcp: new(Enabled: false),
+ Host: new(
+ Cors: null,
+ Authentication: new Config.ObjectModel.AuthenticationOptions(
+ Provider: nameof(EasyAuthType.StaticWebApps),
+ Jwt: null
+ )
+ )
+ ),
+ Entities: new(new Dictionary()),
+ Autoentities: new RuntimeAutoentities(autoentityMap)
+ );
+
+ File.WriteAllText(CUSTOM_CONFIG_FILENAME, configuration.ToJson());
+
+ string[] args = new[] { $"--ConfigFileName={CUSTOM_CONFIG_FILENAME}" };
+ using (TestServer server = new(Program.CreateWebHostBuilder(args)))
+ using (HttpClient client = server.CreateClient())
+ {
+ // Act
+ using HttpRequestMessage restRequest = new(HttpMethod.Get, "/api/magazines");
+ using HttpResponseMessage restResponse = await client.SendAsync(restRequest);
+
+ string item = isPatternFoo ? "title" : "comic_name";
+ string graphqlQuery = $@"
+ {{
+ magazines {{
+ items {{
+ {item}
+ }}
+ }}
+ }}";
+
+ object graphqlPayload = new { query = graphqlQuery };
+ HttpRequestMessage graphqlRequest = new(HttpMethod.Post, "/graphql")
+ {
+ Content = JsonContent.Create(graphqlPayload)
+ };
+ HttpResponseMessage graphqlResponse = await client.SendAsync(graphqlRequest);
+
+ // Assert
+ string expectedResponseFragment = isPatternFoo ? @"""title"":""Vogue""" : @"""comic_name"":""NotVogue""";
+
+ // Verify REST response
+ Assert.AreEqual(HttpStatusCode.OK, restResponse.StatusCode, "REST request to auto-generated entity should succeed");
+
+ string restResponseBody = await restResponse.Content.ReadAsStringAsync();
+ Assert.IsTrue(!string.IsNullOrEmpty(restResponseBody), "REST response should contain data");
+ Assert.IsTrue(restResponseBody.Contains(expectedResponseFragment));
+
+ // Verify GraphQL response
+ Assert.AreEqual(HttpStatusCode.OK, graphqlResponse.StatusCode, "GraphQL request to auto-generated entity should succeed");
+
+ string graphqlResponseBody = await graphqlResponse.Content.ReadAsStringAsync();
+ Assert.IsTrue(!string.IsNullOrEmpty(graphqlResponseBody), "GraphQL response should contain data");
+ Assert.IsFalse(graphqlResponseBody.Contains("errors"), "GraphQL response should not contain errors");
+ Assert.IsTrue(graphqlResponseBody.Contains(expectedResponseFragment));
+ }
+ }
+
+ ///
+ /// Tests that DAB fails if the entities generated from autoentities property
+ /// do not contain unique parameters such as rest path, graphql singular/plural names,
+ /// or if the autoentity pattern conflicts with an existing entity name.
+ ///
+ /// Definition name of the generated entity from autoentities
+ /// GraphQL singular name of the generated entity from autoentities
+ /// GraphQL plural name of the generated entity from autoentities
+ /// REST path of the generated entity from autoentities
+ /// Expected exception message
///
[TestCategory(TestCategory.MSSQL)]
[DataTestMethod]