MSB Database Context
A lightweight and flexible .NET ORM (Object-Relational Mapping) library that provides simple database operations with support for multiple database providers including SQL Server, MySQL, and PostgreSQL,Oracle,IBM Db2,SQLite.
Features
- 🚀 Multi-Database Support: Works with SQL Server, MySQL, and PostgreSQL,Oracle,IBM Db2,SQLite
- 📝 Code-First Approach: Define your models with attributes
- 🔄 CRUD Operations: Full Create, Read, Update, Delete support
- 🔀 Case Conversion: Automatic property-to-column name conversion (Pascal, Snake, Camel case)
- 📊 Complex Data Types: JSON serialization support for complex objects
- 🔁 Async/Sync: Both asynchronous and synchronous method variants
- 📦 Bulk Operations: Efficient bulk insert operations
- 🎯 Stored Procedures: Execute stored procedures with ease
- 🔒 Transaction Support: Built-in transaction handling
- 🛠️ Custom Queries: Execute raw SQL queries when needed
Installation
Install-Package Msb.DatabaseContext
Quick Start
1. Define Your Model
[CaseTypeConversion(CaseType.SNAKE)]
public class User
{
[HasPrimaryKey]
public long Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Contact { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
[WrapperData] // Maps complex object to JSON column
public AddressLog Address { get; set; }
[WrapperData] // Maps list of objects to JSON column
public IList<AddressLog> AddressLogs { get; set; } = new List<AddressLog>();
public UserStatus? Status { get; set; }
public bool? IsActive { get; set; }
public DateTime? CreatedAt { get; set; }
public DateTime? UpdatedAt { get; set; }
[SkipMapping] // Skip mapping for navigation properties
public User Parent { get; set; }
[SkipMapping]
public IList<User> Children { get; set; } = new List<User>();
}
public enum UserStatus
{
Inactive,
Active,
Blocked
}
2. Initialize Database Context
// SQL Server
var connection = new SqlConnection("your-connection-string");
// MySQL
var connection = new MySqlConnection("your-connection-string");
// PostgreSQL
var connection = new NpgsqlConnection("your-connection-string");
var dbContext = new MsbDatabaseContext(connection);
Basic CRUD Operations
Insert
var newUser = new User
{
Name = "John Doe",
Email = "john.doe@example.com",
Contact = "+1-202-555-0147",
UserName = "johndoe",
Password = "SecurePass123",
CreatedAt = DateTime.Now,
Status = UserStatus.Active
};
// Synchronous
User user = connection.Insert(newUser);
// Asynchronous
User user = await connection.InsertAsync(newUser);
Select
// Get all users
IEnumerable<User> users = await connection.SelectAsync<User>();
// Get single user by ID
User user = await connection.SelectOneAsync<User>(1);
Update
user.Status = UserStatus.Inactive;
user.UpdatedAt = DateTime.Now;
user.UserName = "john";
// Synchronous
User updatedUser = connection.Update(user);
// Asynchronous
User updatedUser = await connection.UpdateAsync(user);
Delete
// Synchronous
connection.Delete(user);
// Asynchronous
await connection.DeleteAsync(user);
Advanced Features
Bulk Operations
var bulkUsers = new List<User>() { user1, user2, user3 };
// Synchronous
int count = connection.BulkInsert(bulkUsers);
// Asynchronous
int count = await connection.BulkInsertAsync(bulkUsers);
Custom Queries
// Execute raw SQL
DataTable dataTable = await connection.QueryDataTableAsync("SELECT * FROM users WHERE status = @status",
new { status = UserStatus.Active });
// Convert DataTable to List<T>
IEnumerable<User> users = dataTable.ToList<User>();
Stored Procedures
// Execute stored procedure
IEnumerable<User> users = connection.Execute<User>("SP_Users_GetAll");
// With parameters
User user = connection.ExecuteSingle<object, User>("SP_Users_GetOne", new { Id = 1 });
// Get scalar result
string result = connection.ExecuteScalar<string>("SP_Users_Create", userParams);
Transaction Support
Manual Transaction
connection.Open();
using (var transaction = connection.BeginTransaction())
{
try
{
var result = await connection.RunScalarQueryAsync<string>(
"run_users_create",
userCreate,
dbTransaction: transaction
);
transaction.Commit();
}
catch
{
transaction.Rollback();
throw;
}
finally
{
connection.Close();
}
}
Internal Transaction
string result = await connection.RunScalarQueryAsync<string>(
"run_users_create",
userCreate,
useInternalTransaction: true
);
JSON Data Handling
// Serialize object to JSON
string jsonData = MsbContext.Serialize(userCreate);
// Deserialize JSON to object
UserCreateParams data = MsbContext.Deserialize<UserCreateParams>(jsonData);
Query Parameters
var userParameter = new QueryParameter();
userParameter.Add("name", "John Doe");
userParameter.Add("email", "john.doe@example.com");
userParameter.Add("address", addressObject.Serialize());
string result = await connection.RunScalarQueryAsync<string>("run_users_create", userParameter);
Attributes Reference
Model Attributes
[CaseTypeConversion(CaseType)]
: Converts property names to database column names
CaseType.PASCAL
: PascalCase (default)
CaseType.SNAKE
: snake_case
CaseType.CAMEL
: camelCase
[MappedName("column_name")]
: Maps property to specific column name
[HasPrimaryKey]
: Defines primary key (default is "Id")
[SkipMapping]
: Excludes property from database mapping
[WrapperData]
: Maps complex objects/lists to JSON columns
Data Conversion Utilities
// DataTable to List<T>
IEnumerable<User> users = MsbContext.ToList<User>(dataTable);
// Class to DataTable
DataTable data = MsbContext.ToDataTable(users);
// Object conversion (DTO mapping)
UserDto userDto = MsbContext.ConvertAs<User, UserDto>(user);
IEnumerable<UserDto> userDtos = MsbContext.ConvertListAs<User, UserDto>(users);
// ExpandoObject to class
User user = MsbContext.ToConvert<User>(expandoObject);
// MsbData to class
User user = MsbContext.ToConvert<User>(msbData);
Working with MsbData
For dynamic data access without strongly-typed models:
IEnumerable<MsbData> users = await connection.RunTableQueryAsync("run_users_get_all");
foreach (var user in users)
{
Console.WriteLine($"Id: {user.Get<int>("id")}");
Console.WriteLine($"Name: {user.Get<string>("name")}");
Console.WriteLine($"Email: {user.Get<string>("email")}");
Console.WriteLine($"Address: {user.Get<AddressLog>("address")}");
}
Connection String Examples
SQL Server
var connection = new SqlConnection(
"Data Source=SERVER\\INSTANCE;Initial Catalog=DATABASE;Integrated Security=True;TrustServerCertificate=True"
);
MySQL
var connection = new MySqlConnection(
"Server=localhost;Database=DATABASE;User ID=root;Password=PASSWORD;"
);
PostgreSQL
var connection = new NpgsqlConnection(
"server=localhost;port=5432;database=DATABASE;user id=USER;password=PASSWORD"
);
Best Practices
- Use Async Methods: Prefer async methods for better performance in web applications
- Transaction Management: Use transactions for operations that require consistency
- Connection Management: Always dispose connections properly or use using statements
- Parameter Binding: Use parameterized queries to prevent SQL injection
- Case Conversion: Use consistent case conversion across your models
- Complex Objects: Use
[WrapperData]
for objects that should be stored as JSON
CRUD Operations
Method |
Sync/Async |
Use Case |
Example |
Insert<T>(T entity) |
Sync |
Insert single entity and return inserted object |
User user = connection.Insert(newUser); |
InsertAsync<T>(T entity) |
Async |
Insert single entity asynchronously |
User user = await connection.InsertAsync(newUser); |
Select<T>() |
Sync |
Get all records of type T |
IEnumerable<User> users = connection.Select<User>(); |
SelectAsync<T>() |
Async |
Get all records of type T asynchronously |
IEnumerable<User> users = await connection.SelectAsync<User>(); |
SelectOne<T>(object id) |
Sync |
Get single record by primary key |
User user = connection.SelectOne<User>(1); |
SelectOneAsync<T>(object id) |
Async |
Get single record by primary key asynchronously |
User user = await connection.SelectOneAsync<User>(1); |
Update<T>(T entity) |
Sync |
Update existing entity and return updated object |
User updatedUser = connection.Update(user); |
UpdateAsync<T>(T entity) |
Async |
Update existing entity asynchronously |
User updatedUser = await connection.UpdateAsync(user); |
Delete<T>(T entity) |
Sync |
Delete entity from database |
connection.Delete(user); |
DeleteAsync<T>(T entity) |
Async |
Delete entity from database asynchronously |
await connection.DeleteAsync(user); |
Bulk Operations
Method |
Sync/Async |
Use Case |
Example |
BulkInsert<T>(IEnumerable<T> entities) |
Sync |
Insert multiple records efficiently |
int count = connection.BulkInsert(userList); |
BulkInsertAsync<T>(IEnumerable<T> entities) |
Async |
Insert multiple records efficiently (async) |
int count = await connection.BulkInsertAsync(userList); |
Custom SQL Query Methods
Method |
Sync/Async |
Use Case |
Example |
Query<T>(string sql, object param) |
Sync |
Execute custom SQL and map to objects |
var users = connection.Query<User>("SELECT * FROM users WHERE status = @status", new { status = 1 }); |
QueryAsync<T>(string sql, object param) |
Async |
Execute custom SQL and map to objects (async) |
var users = await connection.QueryAsync<User>("SELECT * FROM users WHERE status = @status", new { status = 1 }); |
QuerySingle<T>(string sql, object param) |
Sync |
Execute SQL and return single object |
var user = connection.QuerySingle<User>("SELECT * FROM users WHERE id = @id", new { id = 1 }); |
QuerySingleAsync<T>(string sql, object param) |
Async |
Execute SQL and return single object (async) |
var user = await connection.QuerySingleAsync<User>("SELECT * FROM users WHERE id = @id", new { id = 1 }); |
QueryDataTable(string sql, object param) |
Sync |
Execute SQL and return DataTable |
DataTable dt = connection.QueryDataTable("SELECT * FROM users"); |
QueryDataTableAsync(string sql, object param) |
Async |
Execute SQL and return DataTable (async) |
DataTable dt = await connection.QueryDataTableAsync("SELECT * FROM users"); |
QueryRunCount(string sql, object param) |
Sync |
Execute SQL and return affected row count |
int count = connection.QueryRunCount("INSERT INTO users(name) VALUES(@name)", new { name = "John" }); |
QueryRunCountAsync(string sql, object param) |
Async |
Execute SQL and return affected row count (async) |
int count = await connection.QueryRunCountAsync("INSERT INTO users(name) VALUES(@name)", new { name = "John" }); |
Stored Procedure Methods
Method |
Sync/Async |
Use Case |
Example |
Execute(string procedureName, object param) |
Sync |
Execute stored procedure, return dynamic results |
var results = connection.Execute("SP_GetUsers"); |
ExecuteAsync(string procedureName, object param) |
Async |
Execute stored procedure, return dynamic results (async) |
var results = await connection.ExecuteAsync("SP_GetUsers"); |
Execute<T>(string procedureName, object param) |
Sync |
Execute stored procedure, map to typed objects |
IEnumerable<User> users = connection.Execute<User>("SP_GetUsers"); |
ExecuteAsync<T>(string procedureName, object param) |
Async |
Execute stored procedure, map to typed objects (async) |
IEnumerable<User> users = await connection.ExecuteAsync<User>("SP_GetUsers"); |
ExecuteSingle(string procedureName, object param) |
Sync |
Execute stored procedure, return single dynamic result |
var user = connection.ExecuteSingle("SP_GetUser", new { Id = 1 }); |
ExecuteSingleAsync(string procedureName, object param) |
Async |
Execute stored procedure, return single dynamic result (async) |
var user = await connection.ExecuteSingleAsync("SP_GetUser", new { Id = 1 }); |
ExecuteSingle<TParam, TResult>(string procedureName, TParam param) |
Sync |
Execute stored procedure with typed parameters and result |
User user = connection.ExecuteSingle<object, User>("SP_GetUser", new { Id = 1 }); |
ExecuteSingleAsync<TParam, TResult>(string procedureName, TParam param) |
Async |
Execute stored procedure with typed parameters and result (async) |
User user = await connection.ExecuteSingleAsync<object, User>("SP_GetUser", new { Id = 1 }); |
ExecuteScalar<T>(string procedureName, object param) |
Sync |
Execute stored procedure, return scalar value |
int count = connection.ExecuteScalar<int>("SP_GetUserCount"); |
ExecuteScalarAsync<T>(string procedureName, object param) |
Async |
Execute stored procedure, return scalar value (async) |
int count = await connection.ExecuteScalarAsync<int>("SP_GetUserCount"); |
ExecuteScalar<TParam, TResult>(string procedureName, TParam param) |
Sync |
Execute stored procedure with typed parameters, return scalar |
string result = connection.ExecuteScalar<UserParams, string>("SP_CreateUser", userParams); |
ExecuteScalarAsync<TParam, TResult>(string procedureName, TParam param) |
Async |
Execute stored procedure with typed parameters, return scalar (async) |
string result = await connection.ExecuteScalarAsync<UserParams, string>("SP_CreateUser", userParams); |
ExecuteDataTable(string procedureName, object param) |
Sync |
Execute stored procedure, return DataTable |
DataTable dt = connection.ExecuteDataTable("SP_GetUsers"); |
ExecuteDataTableAsync(string procedureName, object param) |
Async |
Execute stored procedure, return DataTable (async) |
DataTable dt = await connection.ExecuteDataTableAsync("SP_GetUsers"); |
ExecuteCountQuery(string procedureName, object param) |
Sync |
Execute stored procedure, return affected row count |
int count = connection.ExecuteCountQuery("SP_CreateUser", userParams); |
ExecuteCountQueryAsync(string procedureName, object param) |
Async |
Execute stored procedure, return affected row count (async) |
int count = await connection.ExecuteCountQueryAsync("SP_CreateUser", userParams); |
Function-Based Query Methods (run_ prefix)
Method |
Sync/Async |
Use Case |
Example |
RunDataTable(string functionName, object param) |
Sync |
Execute database function, return DataTable |
DataTable dt = connection.RunDataTable("run_get_users"); |
RunDataTableAsync(string functionName, object param) |
Async |
Execute database function, return DataTable (async) |
DataTable dt = await connection.RunDataTableAsync("run_get_users"); |
RunScalarQuery<T>(string functionName, object param) |
Sync |
Execute database function, return scalar value |
string result = connection.RunScalarQuery<string>("run_create_user", userParams); |
RunScalarQueryAsync<T>(string functionName, object param) |
Async |
Execute database function, return scalar value (async) |
string result = await connection.RunScalarQueryAsync<string>("run_create_user", userParams); |
RunTableQuery<T>(string functionName, object param) |
Sync |
Execute database function, map to typed objects |
IEnumerable<User> users = connection.RunTableQuery<User>("run_get_users"); |
RunTableQueryAsync<T>(string functionName, object param) |
Async |
Execute database function, map to typed objects (async) |
IEnumerable<User> users = await connection.RunTableQueryAsync<User>("run_get_users"); |
RunTableQuery(string functionName, object param) |
Sync |
Execute database function, return MsbData objects |
IEnumerable<MsbData> users = connection.RunTableQuery("run_get_users"); |
RunTableQueryAsync(string functionName, object param) |
Async |
Execute database function, return MsbData objects (async) |
IEnumerable<MsbData> users = await connection.RunTableQueryAsync("run_get_users"); |
RunTableQuerySingle<TParam, TResult>(string functionName, TParam param) |
Sync |
Execute database function, return single typed object |
User user = connection.RunTableQuerySingle<object, User>("run_get_user", new { id = 1 }); |
RunTableQuerySingleAsync<TParam, TResult>(string functionName, TParam param) |
Async |
Execute database function, return single typed object (async) |
User user = await connection.RunTableQuerySingleAsync<object, User>("run_get_user", new { id = 1 }); |
RunTableQuerySingle(string functionName, object param) |
Sync |
Execute database function, return single MsbData object |
MsbData user = connection.RunTableQuerySingle("run_get_user", new { id = 1 }); |
RunTableQuerySingleAsync(string functionName, object param) |
Async |
Execute database function, return single MsbData object (async) |
MsbData user = await connection.RunTableQuerySingleAsync("run_get_user", new { id = 1 }); |
Utility and Conversion Methods
Method |
Static/Instance |
Use Case |
Example |
MsbContext.Serialize(object obj) |
Static |
Convert object to JSON string |
string json = MsbContext.Serialize(userObject); |
MsbContext.Deserialize<T>(string json) |
Static |
Convert JSON string to object |
User user = MsbContext.Deserialize<User>(jsonString); |
MsbContext.ToList<T>(DataTable dataTable) |
Static |
Convert DataTable to List of objects |
IEnumerable<User> users = MsbContext.ToList<User>(dataTable); |
MsbContext.ToListAsync<T>(DataTable dataTable) |
Static |
Convert DataTable to List of objects (async) |
IEnumerable<User> users = await MsbContext.ToListAsync<User>(dataTable); |
MsbContext.ToDataTable<T>(IEnumerable<T> list) |
Static |
Convert List of objects to DataTable |
DataTable dt = MsbContext.ToDataTable(userList); |
MsbContext.ConvertAs<TSource, TTarget>(TSource source) |
Static |
Convert one object type to another |
UserDto dto = MsbContext.ConvertAs<User, UserDto>(user); |
MsbContext.ConvertListAs<TSource, TTarget>(IEnumerable<TSource> list) |
Static |
Convert list of one type to another |
IEnumerable<UserDto> dtos = MsbContext.ConvertListAs<User, UserDto>(users); |
MsbContext.ToConvert<T>(ExpandoObject obj) |
Static |
Convert ExpandoObject to typed object |
User user = MsbContext.ToConvert<User>(expandoObject); |
MsbContext.ToConvert<T>(MsbData data) |
Static |
Convert MsbData to typed object |
User user = MsbContext.ToConvert<User>(msbData); |
dataTable.ToList<T>() |
Extension |
Extension method to convert DataTable to List |
IEnumerable<User> users = dataTable.ToList<User>(); |
object.Serialize() |
Extension |
Extension method to serialize object to JSON |
string json = userObject.Serialize(); |
string.Deserialize<T>() |
Extension |
Extension method to deserialize JSON to object |
User user = jsonString.Deserialize<User>(); |
MsbData Methods
Method |
Use Case |
Example |
msbData.Get<T>(string columnName) |
Get typed value from MsbData object |
string name = userData.Get<string>("name"); |
msbData.Get<T>(string columnName, T defaultValue) |
Get typed value with default fallback |
int age = userData.Get<int>("age", 0); |
Transaction Parameters
Most methods support additional transaction parameters:
Parameter |
Use Case |
Example |
dbTransaction |
Use existing transaction |
connection.InsertAsync(user, dbTransaction: transaction) |
useInternalTransaction |
Use automatic internal transaction |
connection.InsertAsync(user, useInternalTransaction: true) |
Method Usage Patterns
Pattern 1: Direct Connection Methods
// Use connection directly for operations
var result = connection.Insert(entity);
var result = await connection.InsertAsync(entity);
Pattern 2: Database Context Methods
// Use MsbDatabaseContext wrapper
var result = connection.Insert(entity);
var result = await connection.InsertAsync(entity);
Pattern 3: Function vs Stored Procedure
// Database functions (typically prefixed with "run_")
var result = connection.RunTableQuery<User>("run_get_users");
// Stored procedures
var result = connection.Execute<User>("SP_GetUsers");