Skip to content
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

FromSqlRaw returning null entity if all column values are null #19537

Closed
joshvote opened this issue Jan 9, 2020 · 3 comments · Fixed by #20280
Closed

FromSqlRaw returning null entity if all column values are null #19537

joshvote opened this issue Jan 9, 2020 · 3 comments · Fixed by #20280
Assignees
Labels
area-query breaking-change closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported type-bug
Milestone

Comments

@joshvote
Copy link

joshvote commented Jan 9, 2020

When using FromSqlRaw on a keyless entity and the underlying SQL result returns columns where EVERY column value is NULL - FromSqlRaw returns a null entity instead of an entity with all of its properties set to null.

Steps to reproduce

Say I have the following Models

public class Car
{
  public int CarID { get; set; }
  public string Name { get; set; }
}
public class CarView
{
  public string Name { get; set; }
  public int? Count { get; set; }
  public int? Price { get; set; }
}

Configured using

modelBuilder.Entity<Car>(entity =>
{
  entity.ToTable("Cars", "test");
  entity.HasKey(e => e.CarID);
  entity.Property(e => e.CarID).ValueGeneratedNever();
});

modelBuilder.Entity<CarView>(entity =>
{
  entity.HasNoKey();
});

If we simulate an SQL query returning NULL for all of the CarView properties

dc.Cars.Add(new Car { CarID = 1, Name = null });
await dc.SaveChangesAsync();

// Fake query simulating a response where ALL of the columns were NULL
List<CarView> allNullFields = await dc.CarViews.FromSqlRaw("SELECT NULL as [Name], NULL AS [Count], NULL AS [Price] FROM [test].[Cars]").ToListAsync();

// Fake query simulating a response where SOME but not all of the columns were NULL
List<CarView> someNullFields = await dc.CarViews.FromSqlRaw("SELECT NULL as [Name], 123 AS [Count], NULL AS [Price] FROM [test].[Cars]").ToListAsync();

Assert.Single(someNullFields); // success
Assert.NotNull(someNullFields.First()); // success (also all properties are mapped correctly)

Assert.Single(allNullFields); // success
Assert.NotNull(allNullFields.First()); // fails - the parsed list is a single element which is null

Full project is on a custom branch at https://github.com/joshvote/efcorerawsqlbug/tree/allnullresponse

Further technical details

EF Core version: 3.1
Database provider: Microsoft.EntityFrameworkCore.SqlServer
Target framework: .NET Core 3.1
Operating system: Windows 10
IDE: (e.g. Visual Studio 2019 16.4.2)

@ajcvickers
Copy link
Member

Note for team: I was able to reproduce this. This isn't a behavior it would be possible to have when the entity type has a key, since it must be non-null. This may be why we are only seeing this now with keyless entities.

@ajcvickers ajcvickers added this to the 5.0.0 milestone Jan 17, 2020
@smitpatel smitpatel removed this from the 5.0.0 milestone Feb 5, 2020
@ajcvickers
Copy link
Member

Note for team: let's re-discuss. Consider the example below:

public static class ThreeOne
{
    public static void Main()
    {
        // using (var context = new SomeDbContext())
        // {
        //     context.Database.EnsureDeleted();
        //     context.Database.EnsureCreated();
        //
        //     context.Add(new Product { Name = null, Description = null });
        //     
        //     context.SaveChanges();
        // }

        using (var context = new SomeDbContext())
        {
            var products = context.Set<Product>().ToList();
            Console.WriteLine(products.Count);
            Console.WriteLine(products[0] == null);
        }
    }
}

public class SomeDbContext : DbContext
{
    private static readonly ILoggerFactory
        Logger = LoggerFactory.Create(x => x.AddConsole()); //.SetMinimumLevel(LogLevel.Debug));

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Product>().HasNoKey();
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        => optionsBuilder
            .UseLoggerFactory(Logger)
            .EnableSensitiveDataLogging()
            .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Test;ConnectRetryCount=0");
}

public class Product
{
    //public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
}

This returns a list with a null instance, rather than an instance with two null values.

@ajcvickers ajcvickers added this to the 5.0.0 milestone Feb 10, 2020
@smitpatel smitpatel assigned maumar and unassigned smitpatel Feb 20, 2020
@smitpatel smitpatel assigned smitpatel and unassigned maumar Mar 13, 2020
@smitpatel
Copy link
Member

Poaching

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-query breaking-change closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported type-bug
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants