borisdj / EFCore.BulkExtensions

Entity Framework EF Core efcore Bulk Batch Extensions with BulkCopy in .Net for Insert Update Delete Read (CRUD), Truncate and SaveChanges operations on SQL Server, PostgreSQL, MySQL, SQLite
https://codis.tech/efcorebulk
Other
3.57k stars 578 forks source link

BulkRead does not work for views #1430

Open arjensteinhauer opened 4 months ago

arjensteinhauer commented 4 months ago

Hi, when I try to use BulkRead to read entities from a SQL Server view, the method throws an exception 'Entity does not contain a table name'. When I look into the code, I think the IEntityType.GetTableName() form Entity Framework Core is used. This method indeed will return null for entities mapped to SQL views. IEntityType.GetViewName() should probably be used instead.

Is it possible to add support to BulkExtensions.BulkRead to read entities from a view? That would be great!

Versions being used by me at the moment:

entity definition:

public class MyViewItem
{
    public long Id { get; set; }

    public int TenantId { get; set; }

    [Required]
    [MaxLength(100)]
    public string Description { get; set; }
}

DbContext:

public class MyContext : DbContext
{
    public DbSet<MyViewItem> MyViewItems { get; set; }

    public MyContext(DbContextOptions<MyContext> options) : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<MyViewItem>(entity =>
        {
            entity.HasKey(item => new { item.TenantId, item.Id });
            entity.ToView("MyView");
        });
    }
}

Code to read (which throws the exception):

public async Task<IEnumerable<MyViewItem>> ReadViewItems(List<long> ids)
{
    var tenantId = 1;
    var entities = ids
        .Select(id => new MyViewItem { Id = id, TenantId = tenantId })
        .ToList();

    using (var context = _contextFactory.Create())
    {
        await context.BulkReadAsync(entities, config =>
        {
            config.UpdateByProperties = new List<string> { nameof(MyViewItem.TenantId), nameof(MyViewItem.Id) };
        }).ConfigureAwait(false);

        return entities;
    }
}

SQL Server view

CREATE OR ALTER VIEW [MyView] AS
SELECT [TenantId]
     , [Id]
     , [Description]
FROM   [MyTable]
borisdj commented 3 months ago

Will look into it.

arjensteinhauer commented 1 month ago

Hi @borisdj, do you have an update on this?

The support for bulk reading from a sql view should be fairly easy I think. The when theIEntityType.GetTableName() from Entity Framework Core returns null, IEntityType.GetViewName() can be used as a second check?