{"record":{"id":"215f3a2302602e8e","repo":"dotnet/efcore","slug":"defaultifempty-cannot-be-applied-after-a-client","errorCode":null,"errorMessage":"'DefaultIfEmpty' cannot be applied after a client-evaluated projection. Consider applying 'DefaultIfEmpty' before last 'Select' or use 'AsEnumerable' before 'DefaultIfEmpty' to apply it on client-side.","messagePattern":"'DefaultIfEmpty' cannot be applied after a client-evaluated projection\\. Consider applying 'DefaultIfEmpty' before last 'Select' or use 'AsEnumerable' before 'DefaultIfEmpty' to apply it on client-side\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/EFCore.InMemory/Query/Internal/InMemoryQueryExpression.cs","lineNumber":463,"sourceCode":"        {\n            throw new InvalidOperationException(InMemoryStrings.SetOperationsNotAllowedAfterClientEvaluation);\n        }\n\n        ServerQueryExpression = Call(\n            setOperationMethodInfo.MakeGenericMethod(typeof(ValueBuffer)), ServerQueryExpression, source2.ServerQueryExpression);\n    }\n\n    /// <summary>\n    ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to\n    ///     the same compatibility standards as public APIs. It may be changed or removed without notice in\n    ///     any release. You should only use it directly in your code with extreme caution and knowing that\n    ///     doing so can result in application failures when updating to a new Entity Framework Core release.\n    /// </summary>\n    public virtual void ApplyDefaultIfEmpty()\n    {\n        if (_clientProjections.Count != 0)\n        {\n            throw new InvalidOperationException(InMemoryStrings.DefaultIfEmptyAppliedAfterProjection);\n        }\n\n        ServerQueryExpression = Call(\n            EnumerableMethods.DefaultIfEmptyWithArgument.MakeGenericMethod(typeof(ValueBuffer)),\n            ServerQueryExpression,\n            Constant(new ValueBuffer(Enumerable.Repeat((object?)null, _projectionMappingExpressions.Count).ToArray())));\n\n        ReplaceProjection(\n            _projectionMapping.ToDictionary(\n                kv => kv.Key,\n                kv => kv.Value switch\n                {\n                    EntityProjectionExpression p => MakeEntityProjectionNullable(p),\n\n                    var p when !p.Type.IsNullableType()\n                        => Coalesce(\n                            MakeReadValueNullable(p),\n                            p.Type.GetDefaultValueConstant()),","sourceCodeStart":445,"sourceCodeEnd":481,"githubUrl":"https://github.com/dotnet/efcore/blob/3a2006ef569de08368d59db5e1468aa8f407e4f8/src/EFCore.InMemory/Query/Internal/InMemoryQueryExpression.cs#L445-L481","documentation":"InMemoryQueryExpression.ApplyDefaultIfEmpty checks whether any client projections have been accumulated (_clientProjections.Count != 0). If so, it cannot inject a null-padding DefaultIfEmpty at the server ValueBuffer level because the client projection layer has already reshaped the stream, so it throws DefaultIfEmptyAppliedAfterProjection. The provider needs DefaultIfEmpty to operate on the raw server projection before any client-side Select reshaping.","triggerScenarios":"A LINQ query that applies DefaultIfEmpty (typically via a left join pattern) after a Select that has already triggered client projection evaluation in the InMemory provider.","commonSituations":"Simulating left joins with SelectMany + DefaultIfEmpty where the preceding Select includes a non-translatable expression, or composing DefaultIfEmpty after a group/join that already forced client evaluation. Often surfaces when testing InMemory with queries written for SQL providers.","solutions":["Apply DefaultIfEmpty before the last Select call so the provider can pad ValueBuffers at the server level.","Insert AsEnumerable() before DefaultIfEmpty to perform the default-if-empty logic on the client side.","Restructure the left-join so the DefaultIfEmpty sits directly on the inner sequence before any projection."],"exampleFix":"// before — DefaultIfEmpty after client-projection Select\nvar query = from o in ctx.Orders\n            from p in o.Items.Select(i => new { i.Id, Desc = Format(i.Name) }).DefaultIfEmpty()\n            select new { o.Id, p?.Desc };\n\n// after — apply DefaultIfEmpty on the raw inner sequence first\nvar query = ctx.Orders\n    .SelectMany(o => o.Items.AsQueryable().DefaultIfEmpty(), (o, i) => new { o.Id, Desc = i != null ? Format(i.Name) : null })\n    .AsEnumerable();","handlingStrategy":"validation","validationCode":"// Validate query structure: apply DefaultIfEmpty before any Select that\n// triggers client projection. For left-join patterns, put DefaultIfEmpty\n// directly on the inner sequence.\n// Structural rule: DefaultIfEmpty must see only server-translatable projections.\nvar query = ctx.Orders\n    .SelectMany(o => ctx.Items.Where(i => i.OrderId == o.Id).DefaultIfEmpty(),\n               (o, i) => new { Order = o, Item = i });","typeGuard":null,"tryCatchPattern":"try\n{\n    return query.ToList();\n}\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"DefaultIfEmpty\"))\n{\n    // Move DefaultIfEmpty before the client Select\n    var baseQuery = ctx.Orders.SelectMany(\n        o => ctx.Items.Where(i => i.OrderId == o.Id).DefaultIfEmpty(),\n        (o, i) => new { o, i });\n    return baseQuery.AsEnumerable().Select(projectClient).ToList();\n}","preventionTips":["Apply DefaultIfEmpty directly on the inner sequence in left-join patterns.","Do not chain Select with client-side logic before DefaultIfEmpty.","Use AsEnumerable() before DefaultIfEmpty if the operation must run client-side.","Test left-join query patterns against the InMemory provider."],"tags":["efcore","inmemory","query-translation","defaultifempty","left-join"],"backgroundTag":null,"analyzedSha":"3a2006ef569de08368d59db5e1468aa8f407e4f8","analyzedAt":"2026-08-11T23:42:04.146Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}