-
Notifications
You must be signed in to change notification settings - Fork 3.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Count after Take throws "No column name was specified for column 1 of 't'." #29667
Comments
Which version of EF and SQL Server are you using? If you're on a version under 6.0, please upgrade to at least 6.0. I can't reproduce this with either 6.0 or 7.0 on modern SQL Server; please see the code below, and tweak it to make the failure apparent. Attempted reproawait using var ctx = new BlogContext();
await ctx.Database.EnsureDeletedAsync();
await ctx.Database.EnsureCreatedAsync();
_ = await ctx.Blogs.Take(25).CountAsync();
public class BlogContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.UseSqlServer(@"Server=localhost;Database=test;User=SA;Password=Abcd5678;Connect Timeout=60;ConnectRetryCount=0;Encrypt=false")
.LogTo(Console.WriteLine, LogLevel.Information)
.EnableSensitiveDataLogging();
}
public class Blog
{
public int Id { get; set; }
public string? Name { get; set; }
} |
It's EF 7. I'll get a better repro together. |
I discovered the issue affects specifically Keyless Entities. Here's a Repro: #nullable disable
using System;
using System.Reflection;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.Extensions.Logging;
var ctx = new ApiContext();
//Error: No column name was specified for column 1 of 't'.
var x = new ApiContext().Contacts.Take(25).Count();
Console.WriteLine(x);
public class ApiContext : DbContext
{
protected override void OnConfiguring
(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("server=.;DATABASE=MyTestDataBase;Integrated Security=true;TrustServerCertificate=True;");
optionsBuilder.LogTo(m => Console.WriteLine(m), Microsoft.Extensions.Logging.LogLevel.Debug);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());
}
public DbSet<Contact> Contacts { get; set; }
}
public class Contact
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public partial class ContactMap : IEntityTypeConfiguration<Contact>
{
public void Configure(EntityTypeBuilder<Contact> entity)
{
entity.ToTable("Contacts", "dbo");
//Make it a Keyless Entity
//entity.HasKey(e => e.Id);
entity.HasNoKey();
entity.Property(e => e.FirstName)
.HasMaxLength(50)
.IsUnicode(false);
entity.Property(e => e.LastName)
.HasMaxLength(50)
.IsUnicode(false);
}
} |
Apparently when the entity has a key the SQL produced has a valid column name:
|
Thanks, this indeed repros for keyless entity types. When there's a key we just select that in the subquery, but there isn't we select nothing, which is syntactically incorrect. We could always select out star instead for this case. |
Note that this is a regression from 6.0, where we'd always select all columns, regardless of key/keyless: SELECT COUNT(*)
FROM (
SELECT TOP(@__p_0) [b].[Id], [b].[Name]
FROM [Blogs] AS [b]
) AS [t] |
With milestone 8.0.0 this will be fixed with EFCore 8.0? Is that correct? |
Furthermore this also holds for e.g. table valued functions used in a query which results in a And is there a workaround possible until the bug is fixed? This is sadly a blocker for us to update :-/ |
@maumar to look for workaround. |
sadly there is no good workaround - Count is effectively pruning the projection, so we can't do any tricks to circumvent the issue. Either entity must have a key, or Count must be performed on the client. Note that exec sp_executesql N'SELECT COUNT(*)
FROM (
SELECT TOP(@__p_0) 1 as foo
FROM [SomeTable] AS [c]
) AS [t](x)',N'@__p_0 int',@__p_0=25 works just fine. i.e. we just need to add alias to the "empty" projection to satisfy the sql engine, but that's not something we can force from the user side at the moment. We should either revert to old behavior or force a dummy alias on the empty projection |
… for column 1 of 't'." Problem was that in some cases (e.g. count over keyless entity that has been pushed down) we now generate empty projection in the subquery, where before we were projecting some columns. SQL Server doesn't allow unaliased projection in the subquery, so the fix is to simply add an alias to the empty projection that we generate. Fixes #29667
… for column 1 of 't'." Problem was that in some cases (e.g. count over keyless entity that has been pushed down) we now generate empty projection in the subquery, where before we were projecting some columns. SQL Server doesn't allow unaliased projection in the subquery, so the fix is to simply add an alias to the empty projection that we generate. Fixes #29667
… for column 1 of 't'." Problem was that in some cases (e.g. count over keyless entity that has been pushed down) we now generate empty projection in the subquery, where before we were projecting some columns. SQL Server doesn't allow unaliased projection in the subquery, so the fix is to simply add an alias to the empty projection that we generate. Fixes #29667
… for column 1 of 't'." Problem was that in some cases (e.g. count over keyless entity that has been pushed down) we now generate empty projection in the subquery, where before we were projecting some columns. SQL Server doesn't allow unaliased projection in the subquery, so the fix is to simply add an alias to the empty projection that we generate. Fixes #29667
… for column 1 of 't'." Problem was that in some cases (e.g. count over keyless entity that has been pushed down) we now generate empty projection in the subquery, where before we were projecting some columns. SQL Server doesn't allow unaliased projection in the subquery, so the fix is to simply add an alias to the empty projection that we generate. Fixes #29667
… for column 1 of 't'." (#30134) Problem was that in some cases (e.g. count over keyless entity that has been pushed down) we now generate empty projection in the subquery, where before we were projecting some columns. SQL Server doesn't allow unaliased projection in the subquery, so the fix is to simply add an alias to the empty projection that we generate. Fixes #29667
reopen for potential servicing |
I found similar closed issues surrounding Count with subqueries.
I discovered this passing a Linq query into a 3rd party library which internally performs a Count on the query it is given.
EF Core 7.0 Repro:
Perform a Take(25).CountAsync() on any context DbSet.
You wind up with
Which throws database error "No column name was specified for column 1 of 't'"
This could easily be resolved by adding a column name
AS [t](x)
, such as:EF Core 6.0 does not have this issue as it produces
SELECT TOP(@__p_0) [c].[Column1],[c].[Column2],.....
It seems in 7.0, it was decided to simplify the Count by removing the SELECT fields and just using a hard-coded 1.
SELECT TOP(@__p_0) 1
The text was updated successfully, but these errors were encountered: