{"record":{"id":"7133df313902db2b","repo":"dotnet/efcore","slug":"executeoperationonownedjsonisnotsupported","errorCode":"ExecuteOperationOnOwnedJsonIsNotSupported","errorMessage":"'{operation}' used over owned type '{entityType}' which is mapped to JSON; '{operation}' on JSON-mapped owned entities is not supported. Consider mapping your type as a complex type instead.","messagePattern":"'(.+?)' used over owned type '(.+?)' which is mapped to JSON; '(.+?)' on JSON-mapped owned entities is not supported\\. Consider mapping your type as a complex type instead\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.ExecuteDelete.cs","lineNumber":22,"sourceCode":"using Microsoft.EntityFrameworkCore.Query.SqlExpressions;\n\nnamespace Microsoft.EntityFrameworkCore.Query;\n\npublic partial class RelationalQueryableMethodTranslatingExpressionVisitor\n{\n    /// <inheritdoc />\n    protected override DeleteExpression TranslateExecuteDelete(ShapedQueryExpression source)\n    {\n        source = source.UpdateShaperExpression(new IncludePruner().Visit(source.ShaperExpression));\n\n        if (source.ShaperExpression is not StructuralTypeShaperExpression { StructuralType: IEntityType entityType } shaper)\n        {\n            throw new InvalidOperationException(RelationalStrings.ExecuteDeleteOnNonEntityType);\n        }\n\n        if (entityType.IsMappedToJson())\n        {\n            throw new InvalidOperationException(\n                RelationalStrings.ExecuteOperationOnOwnedJsonIsNotSupported(\"ExecuteDelete\", entityType.DisplayName()));\n        }\n\n        switch (entityType.GetMappingStrategy())\n        {\n            case RelationalAnnotationNames.TptMappingStrategy:\n                throw new InvalidOperationException(\n                    RelationalStrings.ExecuteOperationOnTPT(\n                        nameof(EntityFrameworkQueryableExtensions.ExecuteDelete),\n                        entityType.DisplayName()));\n\n            // Note that we do allow TPC if the target is a leaf type\n            case RelationalAnnotationNames.TpcMappingStrategy when entityType.GetDirectlyDerivedTypes().Any():\n                throw new InvalidOperationException(\n                    RelationalStrings.ExecuteOperationOnTPC(\n                        nameof(EntityFrameworkQueryableExtensions.ExecuteDelete),\n                        entityType.DisplayName()));\n        }","sourceCodeStart":4,"sourceCodeEnd":40,"githubUrl":"https://github.com/dotnet/efcore/blob/dbf9771522148d61a2467854921bd5dc6f6e6916/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.ExecuteDelete.cs#L4-L40","documentation":"Thrown by TranslateExecuteDelete (and TranslateExecuteUpdate setters) when the target entity type is mapped to JSON (an owned entity mapped with ToJson). Bulk modify operations cannot generate partial JSON updates/deletes in this path, so the operation is rejected and the message suggests using a complex type instead.","triggerScenarios":"Calling ExecuteDelete/ExecuteUpdate (via a setter referencing a JSON-owned entity) on an entity whose owned types are mapped to JSON. Example: an Order with OwnsOne(o => o.Address, a => a.ToJson(\"addr\")) and then ExecuteDelete targeting a query that includes the JSON-mapped owned entity, or SetProperty referencing it.","commonSituations":"Adopting JSON column mapping for owned entities and then attempting bulk updates; mixing ToJson with ExecuteUpdate setters that assign the owned object.","solutions":["Map the owned type as a complex type (OwnsOne without ToJson, or ComplexProperty) instead of JSON, which ExecuteUpdate/ExecuteDelete fully support.","Load the entities and update/delete them through the regular change tracker rather than the bulk ExecuteUpdate/ExecuteDelete.","Restrict ExecuteDelete to the owning entity type only, not the JSON-owned entity.","For JSON partial updates, fall back to raw SQL via Database.ExecuteSqlRaw with the provider's JSON functions."],"exampleFix":"// before\nmodelBuilder.Entity<Order>().OwnsOne(o => o.Address, a => a.ToJson(\"address\"));\nawait db.Set<Address>().ExecuteDeleteAsync(); // owned JSON entity\n// after - map as a complex type so bulk ops are supported\nmodelBuilder.Entity<Order>().ComplexProperty(o => o.Address);\nawait db.Orders.Where(o => o.Id == id).ExecuteDeleteAsync();","handlingStrategy":"validation","validationCode":"// Avoid JSON mapping for types you intend to bulk-modify\nforeach (var et in db.Model.GetEntityTypes())\n    if (et.IsMappedToJson()) Console.WriteLine($\"{et.Name} is JSON-mapped; bulk ops unsupported.\");","typeGuard":null,"tryCatchPattern":"try { await db.Set<Address>().ExecuteDeleteAsync(); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"mapped to JSON\"))\n{\n    // load and remove via change tracker, or switch mapping\n    foreach (var a in db.Set<Address>()) db.Remove(a);\n    await db.SaveChangesAsync();\n}","preventionTips":["Prefer ComplexProperty over ToJson for owned objects you need to bulk-update/delete.","Keep JSON-owned entities read-only or update them through SaveChanges.","Document which entities are JSON-backed and disallow bulk ops on them in code review.","For JSON partial updates use raw SQL with provider JSON functions."],"tags":["executedelete","executeupdate","json","owned-types","complex-types","bulk-operations"],"analyzedSha":"dbf9771522148d61a2467854921bd5dc6f6e6916","analyzedAt":"2026-08-06T20:46:03.226Z","schemaVersion":2},"datasetVersion":"2026-08-07T02:17:10.218Z"}