Tutorials ADO.NET Core Tutorial
Multi-Database Architecture — Complete Guide
Multi-Database Architecture — Complete Guide: free step-by-step lesson with examples, common mistakes, and interview tips — part of ADO.NET Core Tutorial on Toolliyo Academy.
On this page
Introduction
Multi-Database Architecture — Complete Guide is essential for .NET developers building ShopNest.DataAccess — Enterprise High-Performance Data Platform — Toolliyo's 100-article ADO.NET Core master path covering SqlConnection, stored procedures, transactions, connection pooling, ASP.NET Core integration, Azure SQL, and ten enterprise portfolio projects. Every article includes minimum two enterprise real-world examples (ICICI banking, TCS ERP reporting, insurance batch, legacy modernization).
In Indian delivery projects (TCS, Infosys, Wipro), interviewers expect multi-database architecture with real banking transfers, ERP GL reports, or legacy stored procedure modernization — not toy animal demos. This article delivers production depth on Dashboard Reporting.
After this article you will
- Explain Multi-Database Architecture in plain English and in SQL Server / ADO.NET terms
- Implement multi-database architecture in ShopNest.DataAccess — Enterprise High-Performance Data Platform (Dashboard Reporting)
- Compare SQL-concat / sync anti-patterns vs production-ready parameterized async ADO.NET
- Answer fresher, mid-level, and senior ADO.NET and SQL Server interview questions confidently
- Connect this lesson to Article 65 and the 100-article ADO.NET Core roadmap
Prerequisites
- Software: .NET 8 SDK, SQL Server Express / LocalDB or Docker, SSMS or Azure Data Studio
- Knowledge: C# basics and SQL Server
- Previous: Article 63 — Data Warehousing Concepts — Complete Guide
- Time: 28 min reading + 30–45 min hands-on in SSMS
Concept deep-dive
Level 1 — Analogy
ADO.NET is a direct phone line to SQL Server — your C# speaks SQL through SqlConnection without an ORM translator in the middle.
Level 2 — Technical
Multi-Database Architecture establishes ShopNest.DataAccess foundations — SqlClient stack, connection strings, and when raw ADO.NET beats EF Core for Dashboard Reporting.
Level 3 — Data platform view
[ASP.NET Core API / MVC Controller]
▼
[Application Service — IOrderRepository interface]
▼
[ADO.NET Repository — SqlConnection + SqlCommand + SqlParameter]
▼
[SQL Server — Tables · Indexes · Stored Procedures · Transactions]
▼
[Connection Pool · Read Replica · Azure SQL · Serilog + SQL Profiler]
Common misconceptions
❌ MYTH: ADO.NET is obsolete — always use EF Core.
✅ TRUTH: ADO.NET wins for stored procedures, bulk load, streaming reports, and legacy SQL — EF Core for rapid CRUD.
❌ MYTH: String concatenation is fine if you escape quotes.
✅ TRUTH: Always SqlParameter — SQL injection is the #1 data breach vector in Indian banking apps.
❌ MYTH: Sync database calls are fine in ASP.NET Core.
✅ TRUTH: Use async ADO.NET end-to-end — sync calls block thread pool under load.
Project structure
ShopNest.DataAccess/
├── src/
│ ├── ShopNest.DataAccess.Api/ ← ASP.NET Core Web API
│ ├── ShopNest.DataAccess.Core/ ← Repository interfaces + DTOs
│ ├── ShopNest.DataAccess.AdoNet/ ← SqlConnection, SPs, transactions
│ ├── ShopNest.DataAccess.Reports/ ← Streaming readers, GL reports
│ └── ShopNest.DataAccess.Tests/ ← Testcontainers SQL integration
├── sql/
│ ├── migrations/
│ └── stored-procedures/ ← usp_Orders_*, usp_Payments_*
└── docker-compose.yml ← SQL Server 2022
Hands-on implementation — Dashboard Reporting
Write Multi-Database Architecture in ShopNest.DataAccess for Dashboard Reporting: SqlConnection/SqlCommand with parameters, async calls, and verify in SSMS with execution plan.
- Open ShopNest.DataAccess repository for this lesson module.
- Use SqlConnection with await using and connection string from IConfiguration.
- Add SqlParameter for every user input — never string concatenation.
- Use ExecuteReaderAsync for reads; transactions for multi-statement writes.
- Verify in SSMS — check execution plan, row counts, and connection pool metrics.
Anti-pattern (SQL concat, sync calls, DataSet for huge reports)
// ❌ BAD — SQL concat, sync call, no disposal
public List<Order> GetOrders(string status) {
var conn = new SqlConnection(_connStr);
conn.Open();
var cmd = new SqlCommand("SELECT * FROM Orders WHERE Status = '" + status + "'", conn);
var reader = cmd.ExecuteReader(); // sync, blocks thread pool
// connection never disposed — pool exhaustion under load
return Parse(reader);
}
Production-style ADO.NET data access
// ✅ CORRECT — Multi-Database Architecture on ShopNest (Dashboard Reporting)
public async Task<IReadOnlyList<OrderDto>> GetByStatusAsync(string status, CancellationToken ct) {
await using var conn = new SqlConnection(_config.GetConnectionString("ShopNestDb"));
await conn.OpenAsync(ct);
await using var cmd = new SqlCommand("usp_Orders_GetByStatus", conn) {
CommandType = CommandType.StoredProcedure
};
cmd.Parameters.Add("@Status", SqlDbType.NVarChar, 20).Value = status;
var list = new List<OrderDto>();
await using var reader = await cmd.ExecuteReaderAsync(ct);
while (await reader.ReadAsync(ct))
list.Add(new OrderDto(reader.GetInt32(0), reader.GetDecimal(1), reader.GetString(2)));
return list;
}
Complete example
// Multi-Database Architecture — ShopNest.DataAccess (Dashboard Reporting)
await using var conn = new SqlConnection(_connectionString);
await conn.OpenAsync(ct);
ADO.NET vs EF Core vs Dapper — when to use which
| Criteria | ADO.NET Core | EF Core | Dapper |
|---|---|---|---|
| Performance (hot path) | Fastest — zero ORM overhead | Slower — change tracker, LINQ translation | Near ADO.NET — thin mapper |
| SQL control | Full — you write every SQL line | Partial — LINQ to SQL, migrations | Full SQL strings + mapping |
| Dev speed | Slower — more boilerplate | Fastest — migrations, conventions | Fast for reads/writes |
| Enterprise use | Banking SPs, reporting, legacy | Greenfield CRUD apps | High-perf APIs, read models |
| ShopNest.DataAccess | Payments ledger, GL reports | Admin CRUD, Identity | Analytics read APIs |
Rule of thumb: EF Core for productivity; ADO.NET for performance-critical SQL, stored procedures, bulk ops, and legacy SP bridges.
SQL performance and connection management — Multi-Database Architecture
- Connection pooling — default enabled; never disable without load testing; watch pool exhaustion (error 10053/10054)
- Parameterized queries — always use SqlParameter; prevents SQL injection and enables plan cache reuse
- Async — ExecuteReaderAsync/ExecuteNonQueryAsync free thread pool under load
- CommandBehavior.SequentialAccess — stream large BLOB/text columns without loading full row into memory
- Indexes — align with WHERE/JOIN columns; use SQL Server DMVs to find missing indexes
Real-World Example 1 — Insurance Claims Batch Processing
MANDATORY enterprise scenario (Insurance (LIC-style)): Multi-Database Architecture in ShopNest.DataAccess Dashboard Reporting.
Business problem
Nightly batch validates 500K claims against policy rules. SqlBulkCopy inserts staging rows; stored procedure usp_ValidateClaims runs set-based SQL; invalid claims roll back in one transaction per batch of 5,000.
Architecture
CSV ingest → SqlBulkCopy → Staging.Claims
→ BEGIN TRANSACTION per batch
→ EXEC usp_ValidateClaims @BatchId
→ COMMIT or ROLLBACK + ErrorLog
Production ADO.NET code
using var bulk = new SqlBulkCopy(conn, SqlBulkCopyOptions.TableLock, tx)
{
DestinationTableName = "Staging.Claims",
BatchSize = 5000,
BulkCopyTimeout = 600
};
await bulk.WriteToServerAsync(dataTable, ct);
await using var validate = new SqlCommand("usp_ValidateClaims", conn, tx) { CommandType = CommandType.StoredProcedure };
validate.Parameters.Add("@BatchId", SqlDbType.Int).Value = batchId;
await validate.ExecuteNonQueryAsync(ct);
Outcome
Batch window reduced from 6 hours to 90 minutes; zero partial batches after explicit transaction boundaries.
Real-World Example 2 — Hospital Patient Records (Apollo-Style)
MANDATORY enterprise scenario (Healthcare): Multi-Database Architecture in ShopNest.DataAccess Dashboard Reporting.
Business problem
Patient vitals, lab results, and billing hit different schemas. ADO.NET multi-result sets from usp_GetPatientDashboard return 3 grids in one round trip — faster than 3 EF Core queries with Include chains.
Architecture
usp_GetPatientDashboard @PatientId → Result set 1: Demographics
→ Result set 2: Latest vitals → Result set 3: Pending bills
Production ADO.NET code
await using var reader = await cmd.ExecuteReaderAsync(ct);
var demo = ReadDemographics(reader);
await reader.NextResultAsync(ct);
var vitals = ReadVitals(reader);
await reader.NextResultAsync(ct);
var bills = ReadBills(reader);
Outcome
Dashboard load 320ms vs 890ms EF Core; HIPAA audit trail via ADO.NET audit interceptor.
ADO.NET with ASP.NET Core — Multi-Database Architecture
Register IDashboardReportingRepository as Scoped in DI. Never hold SqlConnection across requests. Use IConfiguration for connection strings; User Secrets locally, Azure Key Vault in production.
builder.Services.AddScoped<IOrderRepository, OrderRepository>();
builder.Services.AddHealthChecks().AddSqlServer(connectionString);
Stored procedures and SQL safety
Enterprise ShopNest modules use versioned stored procedures (usp_ prefix). Never concatenate user input — always SqlParameter. Log slow queries (>500ms) with Serilog and review execution plans in SSMS.
Common errors & fixes
- SQL built with string concatenation from user input — Use SqlParameter with typed values for every dynamic value.
- Not disposing SqlConnection / SqlDataReader — Use await using for connection, command, and reader — return connections to pool.
- Loading million-row reports into DataTable — Stream with SqlDataReader and yield batches; avoid DataSet for large data.
- Hard-coding connection strings in repository classes — IConfiguration + User Secrets locally; Azure Key Vault in production.
Best practices
- 🟢 SqlParameter for every dynamic value — zero string concatenation
- 🟢 await using for SqlConnection, SqlCommand, SqlDataReader — return to pool
- 🟡 Async ADO.NET end-to-end on ASP.NET Core request paths
- 🟡 Stream large reports with SqlDataReader; avoid DataSet for millions of rows
- 🔴 SqlTransaction for multi-statement financial writes with explicit rollback
- 🔴 Connection strings in Key Vault — never committed to Git
Interview questions
Fresher level
Q1: What is Multi-Database Architecture in ADO.NET Core?
A: Multi-Database Architecture on ShopNest Dashboard Reporting: SqlConnection lifecycle, SqlCommand with parameters, async execution, and disposal for connection pool health.
Q2: ADO.NET vs EF Core — when to use which?
A: ADO.NET for stored procedures, bulk load, streaming reports, and legacy SQL; EF Core for rapid CRUD and migrations. ShopNest uses both.
Q3: How do you prevent SQL injection in ADO.NET?
A: Always SqlParameter with typed SqlDbType — never string concatenation, even for "trusted" internal tools.
Mid / senior level
Q4: Explain connection pooling and why disposal matters.
A: SqlConnection.Close/Dispose returns the physical connection to the pool. Leaked connections exhaust Max Pool Size and cause timeouts.
Q5: How do you handle transactions in ADO.NET?
A: SqlTransaction with try/commit/catch/rollback; choose isolation level (ReadCommitted default); retry deadlocks with Polly.
Q6: How would you optimize a slow stored procedure report?
A: Check execution plan in SSMS, add covering indexes, avoid SELECT *, stream with SqlDataReader, consider read replica for analytics.
Coding round
Implement a parameterized ADO.NET repository method for ShopNest Dashboard Reporting — show SqlConnection, SqlCommand, SqlParameter, async disposal, and one xUnit integration test.
Summary & next steps
- Article 64: Multi-Database Architecture — Complete Guide
- Module: Module 7: Advanced Enterprise Topics · Level: ADVANCED
- Applied to ShopNest.DataAccess — Dashboard Reporting
Previous: Data Warehousing Concepts — Complete Guide
Next: Read Replica Strategies — Complete Guide
Practice: Run today's SQL in SSMS with execution plan — commit with feat(adonet): article-064.
FAQ
Q1: What is Multi-Database Architecture?
Multi-Database Architecture helps ShopNest.DataAccess implement high-performance Dashboard Reporting data access with Microsoft.Data.SqlClient and SQL Server.
Q2: Do I need EF Core to learn ADO.NET?
No — ADO.NET is the foundation. Many Indian banking and ERP projects still rely on stored procedures wrapped in ADO.NET.
Q3: Is ADO.NET asked in interviews?
Yes — SqlConnection, parameters, transactions, and ADO.NET vs EF appear in TCS, Infosys, and product company .NET rounds.
Q4: Which .NET version?
Examples target .NET 8 LTS with Microsoft.Data.SqlClient and async ADO.NET throughout.
Q5: How does this fit ShopNest.DataAccess?
Article 64 strengthens Dashboard Reporting. By Article 100 you have a portfolio-ready enterprise data layer.
Sign in to ask a question or upvote helpful answers.
No questions yet — be the first to ask!