dotnet / dotnet/efcore

Reuse the same value converter instance when configured as type

Open
#33,612 7 comments 0 reactions 1 assignee Assigned to @AndriySvyryd View on GitHub
area-model-building customer-reported
Dominant language
C#
Stars
14.8k
Forks
3.4k
PR merge metrics
PR metrics pending

Description

When a query uses the same parameter in several locations, Entity Framework may not detect the parameter as being the same parameter and will parameterize several instances of the same parameter.

Take for example the following LINQ:
```cs
dbContext.Projects
.Join(
dbContext.ProjectTranslations,
outer => new {
outer.ProjectId,
TranslationId = translationId
},
inner => new {
inner.ProjectId,
inner.TranslationId
},
(outer, inner) => new {
Project = outer,
ProjectTranslation = inner
}
)
.Join(
dbContext.ProjectCategoryTranslations,
outer => new {
outer.Project.ProjectCategoryId,
TranslationId = translationId
},
inner => new {
inner.ProjectCategoryId,
inner.TranslationId
},
(outer, inner) => new {
outer.Project,
outer.ProjectTranslation,
ProjectCategoryTranslation = inner
}
)
.Join(
dbContext.Builders,
outer => outer.Project.BuilderId,
inner => inner.BuilderId,
(outer, inner) => new {
outer.Project,
outer.ProjectTranslation,
outer.ProjectCategoryTranslation,
Builder = inner
}
)
.Join(
dbContext.DirectoryCategoryTranslations,
outer => new {
outer.Builder.DirectoryCategoryId,
TranslationId = translationId
},
inner => new {
inner.DirectoryCategoryId,
inner.TranslationId
},
(outer, inner) => new
{
outer.Project,
outer.ProjectTranslation,
outer.ProjectCategoryTranslation,
outer.Builder,
DirectoryCategoryTranslation = inner,
}
)
.FirstOrDefaultAsync();
```

This will generate the following command:
```
Executed DbCommand (39ms) [Parameters=[
@__translationId_0='?' (DbType = Int32),
@__translationId_0_1='?' (DbType = Int32),
@__translationId_0_2='?' (DbType = Int32),
@__projectId_1='?' (DbType = Int32)
], CommandType='Text', CommandTimeout='30']
```

Now that `EF.Parameter` is available with Entity Framework 9, perhaps this could be improved with an optional name passed to the method. Something like the following?
```cs
dbContext.Projects
.Join(
dbContext.ProjectTranslations,
outer => new {
outer.ProjectId,
TranslationId = EF.Parameter(translationId, "translationId")
},
inner => new {
inner.ProjectId,
inner.TranslationId
},
(outer, inner) => new {
Project = outer,
ProjectTranslation = inner
}
)
.Join(
dbContext.ProjectCategoryTranslations,
outer => new {
outer.Project.ProjectCategoryId,
TranslationId = EF.Parameter(translationId, "translationId")
},
inner => new {
inner.ProjectCategoryId,
inner.TranslationId
},
(outer, inner) => new {
outer.Project,
outer.ProjectTranslation,
ProjectCategoryTranslation = inner
}
)
.Join(
dbContext.Builders,
outer => outer.Project.BuilderId,
inner => inner.BuilderId,
(outer, inner) => new {
outer.Project,
outer.ProjectTranslation,
outer.ProjectCategoryTranslation,
Builder = inner
}
)
.Join(
dbContext.DirectoryCategoryTranslations,
outer => new {
outer.Builder.DirectoryCategoryId,
TranslationId = EF.Parameter(translationId, "translationId")
},
inner => new {
inner.DirectoryCategoryId,
inner.TranslationId
},
(outer, inner) => new
{
outer.Project,
outer.ProjectTranslation,
outer.ProjectCategoryTranslation,
outer.Builder,
DirectoryCategoryTranslation = inner,
}
)
.FirstOrDefaultAsync();
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.