diff --git a/CS/PivotTableBindToData/Pages/Index.razor b/CS/PivotTableBindToData/Pages/Index.razor index 1d9d1c2..6514de4 100644 --- a/CS/PivotTableBindToData/Pages/Index.razor +++ b/CS/PivotTableBindToData/Pages/Index.razor @@ -4,7 +4,6 @@ @using Microsoft.EntityFrameworkCore @using DevExpress.Data.Linq @inject IDbContextFactory SalesContextFactory -@inject IConfiguration Configuration @implements IAsyncDisposable @using DevExpress.Blazor.PivotTable @@ -26,13 +25,16 @@ } else if (DataExists == false) {
-

The Sales table (or the database file) was not found.

+

The Sales table was not found.

@if (IsGenerating) {

Generating 1,000,000 rows, please wait...

}
} +else { +

Checking for data...

+} @code { SalesContext SalesContext { get; set; } @@ -58,7 +60,7 @@ else if (DataExists == false) { IsGenerating = true; StateHasChanged(); - await Task.Run(() => SalesDataGenerator.GenerateAsync(SalesContext, Configuration.GetValue("DataProvider", DataProviders.SQLite.ToString()))); + await Task.Run(() => SalesDataGenerator.GenerateAsync(SalesContext)); CreateDataSource(); DataExists = true; diff --git a/CS/PivotTableBindToData/Program.cs b/CS/PivotTableBindToData/Program.cs index 2d2f5c8..73b0768 100644 --- a/CS/PivotTableBindToData/Program.cs +++ b/CS/PivotTableBindToData/Program.cs @@ -9,16 +9,16 @@ builder.Services.AddDevExpressBlazor(); -var dataProviderSetting = builder.Configuration.GetValue("DataProvider", DataProviders.SQLite.ToString()); +var dataProvider = builder.Configuration.GetValue("DataProvider", DataProviders.SQLite); -if (dataProviderSetting == DataProviders.SQLite.ToString()) { +if (dataProvider == DataProviders.SQLite) { builder.Services.AddDbContextFactory((sp, options) => { var env = sp.GetRequiredService(); var dbPath = Path.Combine(env.ContentRootPath, "sales.db"); options.UseSqlite("Data Source=" + dbPath); }); } -else if (dataProviderSetting == DataProviders.SqlServer.ToString()) { +else if (dataProvider == DataProviders.SqlServer) { builder.Services.AddDbContextFactory(options => { options.UseSqlServer(builder.Configuration.GetConnectionString("SalesDatabase")); }); diff --git a/CS/PivotTableBindToData/SalesDb/DataProviders.cs b/CS/PivotTableBindToData/SalesDb/DataProviders.cs index 04a6755..1faa052 100644 --- a/CS/PivotTableBindToData/SalesDb/DataProviders.cs +++ b/CS/PivotTableBindToData/SalesDb/DataProviders.cs @@ -1,6 +1,16 @@ -namespace PivotTableBindToData.SalesDb { +using System; + +namespace PivotTableBindToData.SalesDb { public enum DataProviders { SQLite, SqlServer } + + public static class DataProvidersExtensions { + public static DataProviders FromEFProviderName(string efProviderName) => efProviderName switch { + "Microsoft.EntityFrameworkCore.Sqlite" => DataProviders.SQLite, + "Microsoft.EntityFrameworkCore.SqlServer" => DataProviders.SqlServer, + _ => throw new NotSupportedException($"Unsupported database provider: '{efProviderName}'.") + }; + } } diff --git a/CS/PivotTableBindToData/SalesDb/SalesDataGenerator.cs b/CS/PivotTableBindToData/SalesDb/SalesDataGenerator.cs index 301583c..7592211 100644 --- a/CS/PivotTableBindToData/SalesDb/SalesDataGenerator.cs +++ b/CS/PivotTableBindToData/SalesDb/SalesDataGenerator.cs @@ -1,5 +1,6 @@ using System.Reflection; using System.Text.RegularExpressions; +using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; #nullable disable @@ -8,34 +9,69 @@ namespace PivotTableBindToData.SalesDb { public static class SalesDataGenerator { public static async Task SalesTableExistsAsync(SalesContext context) { - try { - await context.Sales.Select(s => s.SaleId).Take(1).ToListAsync(); - return true; - } - catch { + if (!await DatabaseExistsAsync(context)) return false; - } + return await SalesTableExistsInDatabaseAsync(context); + } + + static async Task DatabaseExistsAsync(SalesContext context) { + return await context.Database.CanConnectAsync(); + } + + static async Task SalesTableExistsInDatabaseAsync(SalesContext context) { + string sql = GetDataProvider(context) switch { + DataProviders.SQLite => + "SELECT count(*) AS [Value] FROM sqlite_master WHERE type = 'table' AND name = 'Sales'", + DataProviders.SqlServer => + "SELECT count(*) AS [Value] FROM sys.tables WHERE name = 'Sales'", + var provider => throw new NotSupportedException($"Unsupported database provider: '{provider}'.") + }; + + int tableCount = await context.Database.SqlQueryRaw(sql).SingleAsync(); + return tableCount > 0; } - public static async Task GenerateAsync(SalesContext context, string dataProvider) { + public static async Task GenerateAsync(SalesContext context) { + var dataProvider = GetDataProvider(context); string resourceName = dataProvider switch { - nameof(DataProviders.SQLite) => "PivotTableBindToData.SalesDb.Scripts.SQLiteDbGenerator.sql", - nameof(DataProviders.SqlServer) => "PivotTableBindToData.SalesDb.Scripts.SqlServerDbGenerator.sql", + DataProviders.SQLite => "PivotTableBindToData.SalesDb.Scripts.SQLiteDbGenerator.sql", + DataProviders.SqlServer => "PivotTableBindToData.SalesDb.Scripts.SqlServerDbGenerator.sql", _ => "" }; string script = await ReadEmbeddedScriptAsync(resourceName); - var batches = Regex.Split(script, @"^\s*GO\s*$", RegexOptions.Multiline | RegexOptions.IgnoreCase) - .Select(batch => batch.Trim()) - .Where(batch => batch.Length > 0); - context.Database.SetCommandTimeout(0); + if (dataProvider == DataProviders.SqlServer) { + var connectionStringBuilder = new SqlConnectionStringBuilder(context.Database.GetConnectionString()); + string databaseName = connectionStringBuilder.InitialCatalog; + script = script.Replace("{DatabaseName}", databaseName); + connectionStringBuilder.InitialCatalog = "master"; + + await using var connection = new SqlConnection(connectionStringBuilder.ConnectionString); + await connection.OpenAsync(); - foreach (var batch in batches) - await context.Database.ExecuteSqlRawAsync(batch); + var batches = Regex.Split(script, @"^\s*GO\s*$", RegexOptions.Multiline | RegexOptions.IgnoreCase) + .Select(batch => batch.Trim()) + .Where(batch => batch.Length > 0) + .ToList(); + + foreach (var batch in batches) { + await using var command = connection.CreateCommand(); + command.CommandText = batch; + command.CommandTimeout = 0; + await command.ExecuteNonQueryAsync(); + } + return; + } + + context.Database.SetCommandTimeout(0); + await context.Database.ExecuteSqlRawAsync(script); } + static DataProviders GetDataProvider(SalesContext context) => + DataProvidersExtensions.FromEFProviderName(context.Database.ProviderName); + static async Task ReadEmbeddedScriptAsync(string resourceName) { var assembly = Assembly.GetExecutingAssembly(); using var stream = assembly.GetManifestResourceStream(resourceName); diff --git a/CS/PivotTableBindToData/SalesDb/Scripts/SqlServerDbGenerator.sql b/CS/PivotTableBindToData/SalesDb/Scripts/SqlServerDbGenerator.sql index ffe98c9..1b8fe5b 100644 --- a/CS/PivotTableBindToData/SalesDb/Scripts/SqlServerDbGenerator.sql +++ b/CS/PivotTableBindToData/SalesDb/Scripts/SqlServerDbGenerator.sql @@ -1,3 +1,15 @@ +USE [master]; +GO + +IF DB_ID(N'{DatabaseName}') IS NULL +BEGIN + CREATE DATABASE [{DatabaseName}]; +END +GO + +USE [{DatabaseName}]; +GO + IF OBJECT_ID('dbo.Sales', 'U') IS NOT NULL DROP TABLE dbo.Sales; GO diff --git a/CS/PivotTableBindToData/appsettings.json b/CS/PivotTableBindToData/appsettings.json index a8cfe78..1c17406 100644 --- a/CS/PivotTableBindToData/appsettings.json +++ b/CS/PivotTableBindToData/appsettings.json @@ -1,7 +1,7 @@ { "DataProvider": "SQLite", // SQLite or SqlServer "ConnectionStrings": { - "SalesDatabase": "Server=(localdb)\\MSSQLLocalDB;Database=Example;Trusted_Connection=True;" + "SalesDatabase": "Server=(localdb)\\MSSQLLocalDB;Database=DevExpressPivotTableDb;Trusted_Connection=True;" }, "Logging": { "LogLevel": { diff --git a/README.md b/README.md index c6613df..4dec02e 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ # Blazor Pivot Table – Data binding using Entity Framework Core in Server Mode -This example uses [Entity Framework Core](https://learn.microsoft.com/en-us/ef/core/) to bind the [DevExpress Blazor Pivot Table](https://docs.devexpress.com/Blazor/405245/components/pivot-table) to data in Server Mode. This example supports SQLite and SQL Server. The database engine is sonfigured in the `appsettings.json` file. +This example uses [Entity Framework Core](https://learn.microsoft.com/en-us/ef/core/) to bind the [DevExpress Blazor Pivot Table](https://docs.devexpress.com/Blazor/405245/components/pivot-table) to data in Server Mode. This example supports SQLite and SQL Server. The database engine is configured in the `appsettings.json` file. ![Bind DevExpress Blazor Pivot Table to Data with Entity Framework Core](/images/bind-to-data.png)