VTNET.Vitado
7.2.0
dotnet add package VTNET.Vitado --version 7.2.0
NuGet\Install-Package VTNET.Vitado -Version 7.2.0
<PackageReference Include="VTNET.Vitado" Version="7.2.0" />
paket add VTNET.Vitado --version 7.2.0
#r "nuget: VTNET.Vitado, 7.2.0"
// Install VTNET.Vitado as a Cake Addin #addin nuget:?package=VTNET.Vitado&version=7.2.0 // Install VTNET.Vitado as a Cake Tool #tool nuget:?package=VTNET.Vitado&version=7.2.0
ADO.NET Wrapper Library
Introduction
This library is designed to simplify ADO.NET interactions by wrapping around ADO.NET and using the SqlDataReader class to read data. It provides a set of methods for executing queries and stored procedures and mapping the results to objects, making database interactions in your .NET applications more straightforward and efficient.
Commands
The library offers a variety of commands to execute and interact with your database:
The Motivation
The genesis of this library stems from the challenges encountered during a project that required database-first development. The project demanded dealing with complex database requirements, such as seamlessly adapting to changes like renaming parameters in stored procedures without necessitating corresponding modifications in C# code, handling table alterations like adding or removing columns without affecting the C# Insert and Update logic, and more. In essence, the project's data structure was highly dynamic and prone to alterations.
While searching for existing libraries to address these unique demands, it became evident that finding a suitable solution was a daunting task (or my search skills were not up to the challenge! 🤣) Consequently. I embarked on the journey to develop this library to cater to the project's specific needs and ensure a smoother development process. 👌
Simple using
var db = new VitProvider("Data Source=.;Database=...;Integrated Security=sspi;Encrypt=true;TrustServerCertificate=true;Trusted_Connection=True;");
Integration with ASP/Blazor
- You can easily integrate this library into your ASP.NET or Blazor applications. To get started, add the following code to your Startup.cs or Program.cs:
builder.Services.AddVitado("Data Source=.;Initial Catalog=...;MultipleActiveResultSets=True;User Id=...;Password=...");
- But I recommend you to inherit the
IVitProvider
Interface andVitProvider
class even if you don't have any modifications.
//IMyProvider.cs
public interface IMyProvider : IVitProvider{}
//MyProvider.cs
public class MyProvider : VitProvider, IMyProvider{}
builder.Services.AddVitado<IMyProvider, MyProvider>("Data Source=.;Initial Catalog=...;MultipleActiveResultSets=True;User Id=...;Password=...");
Make sure to replace the connection string with your specific database details.
Class Structure
VitProviderBase
: Defining the common architecture for 'Execution'VitProvider
inheritVitProviderBase
: handle life circle connection and add define all Execute methods.- This class only defines the most basic methods (can be used for sqlserver), I recommend you not to use it directly, you should inherit it with your own class for easy modification in the future.
VitProviderScope
inheritVitProvider
: handle life circle scope. Connection of VitProviderScope don't close when end method, you have to close the connection yourself or use 'using'VitProviderBeta
inheritVitProvider
: this class will contain experimental code snippets.VitProviderScope
inheritVitProviderBeta
: likeVitProviderScope
. But, this is beta.
All the classes above allow you to inherit and modify them as you wish.
I no longer differentiate between 'Query' and 'Stored', now there’s only one keyword: 'Execute.'
Execute
Execute
: Execute and return the number of affected rows.Execute<T>
: Execute and return a list of mapped data.ExecuteAsync
: Asynchronously execute and return the number of affected rows.ExecuteAsync<T>
: Asynchronously execute and return a list of mapped data.ExecuteTable
: Execute and return the result as a DataTable.ExecuteTableAsync
: Asynchronously execute and return the result as a DataTable.ExecuteFirst<T>
: Execute and return the first row as a mapped object.ExecuteFirstAsync<T>
: Asynchronously execute and return the first row as a mapped object.ExecuteCell<T>
: Execute and return the first cell of the first row as a mapped object.ExecuteCellAsync<T>
: Asynchronously execute and return the first cell of the first row as a mapped object.
How to Use
Here are examples of how to use the library for querying:
Execute query string
- Simple using
var rowsAffected = db.Execute("select * from [Customers]");
var list = db.Execute<ReportParams>("select * from [Customers]");
var data = db.ExecuteFirst<ReportParams>("select * from [Customers]");
var id = db.ExecuteCell<int>("select * from [Customers]");
var dataTable = db.ExecuteTable("select * from [Customers]");
- parameter in
var rowsAffected = db.Execute("select * from [Customers] where Id = @Id", new(("@id", 69)) );
var list = db.Execute<ReportParams>("select * from [Customers] where Id = @Id", new(("@id", 69)) );
var data = db.ExecuteFirst<ReportParams>("select * from [Customers] where Id = @Id", new(("@id", 69)) );
var id = db.ExecuteCell<int>("select * from [Customers] where Id = @Id", new(("@id", 69)) );
var dataTable = db.ExecuteTable("select * from [Customers] where Id = @Id", new(("@id", 69)));
//you can using parameter in like: new(("@id", 69),("@name","abc")) or new(){ {"@id", 69}, {"@name", "abc"} }
- parameter out
var table_test_stored = provider.Execute("[MyStoredProcedure]",
new(("@InputParam", "xxxx")),
new ()
{
{"@OutputParam", DbType.String},
{"@OutputParamSize", DbType.String, int.MaxValue },
{"@InOutParam", 69 }
}
);
- await async
var rowsAffected = await db.ExecuteAsync("select * from [Customers]");
var list = await db.ExecuteAsync<ReportParams>("select * from [Customers]");
var data = await db.ExecuteFirstAsync<ReportParams>("select * from [Customers]");
var id = await db.ExecuteCellAsync<int>("select * from [Customers]");
var dataTable = await db.ExecuteTableAsync("select * from [Customers]");
var rowsAffected = await db.ExecuteAsync("select * from [Customers] where Id = @Id", new(("@id", 69)) );
var list = await db.ExecuteAsync<ReportParams>("select * from [Customers] where Id = @Id", new(("@id", 69)) );
var data = await db.ExecuteFirstAsync<ReportParams>("select * from [Customers] where Id = @Id", new(("@id", 69)) );
var id = await db.ExecuteCellAsync<int>("select * from [Customers] where Id = @Id", new(("@id", 69)) );
var dataTable = await db.ExecuteTableAsync("select * from [Customers] where Id = @Id", new(("@id", 69)));
//you can using parameter in like: new(("@id", 69),("@name","abc")) or new(){ {"@id", 69}, {"@name", "abc"} }
Execute stored procedure
- Simple using: The usage is similar to the example above, but you only need to provide the above stored procedure and parameters if necessary.
var rowsAffected = db.Execute("SYS_ReportParams");
var list = db.Execute<ReportParams>("SYS_ReportParams");
var data = db.ExecuteFirst<ReportParams>("SYS_ReportParams");
var id = db.ExecuteCell<int>("SYS_ReportParams");
Execute multiple
- This method uses ProviderScope to keep the transaction.
var affected = provider.ExecuteMulti(db =>
{
var rowaffected = 0;
rowaffected += db.Execute("UPDATE [Customers] SET [Name] = @name WHERE id = @id", new(("@name", "test1"),("@id", 60)));
rowaffected += db.Execute("UPDATE [Customers] SET [Name] = @name WHERE id = @id", new(("@name", "test2"), ("@id", 61)));
rowaffected += db.Execute("UPDATE [Customers] SET [Name] = @name WHERE id = @id", new(("@name", "test3"), ("@id", 62)));
rowaffected += db.Execute("UPDATE [Customers] SET [Name] = @name WHERE id = @id", new(("@name", "test4"), ("@id", 63)));
return rowaffected;
});
Console.WriteLine(affected);
Example for custom VitProvider
public class VitProviderScope : VitProvider
{
public VitProvider(string connectionString) : base(connectionString){}
protected override T ExecuteCore<T>(SqlCommand command, Func<SqlCommand, T> func)
{
//Your code...
return base.ExecuteCore(command, func);
}
}
Custom Name Compare (beta: This method may change in the future.)
VitMapper.NameCompare = (string name, string dbName) =>
{
return name.Equals(dbName.Replace("_",""), StringComparison.OrdinalIgnoreCase);
};
Support MySql
- using MySqlConnector
dotnet add package MySqlConnector --version 2.3.7
- new file
MySqlProvider
and inheritanceVitProvider
internal class MySqlProvider : VitProvider
{
public MySqlProvider(string connectionString) : base(connectionString)
{
}
protected override DbConnection Connection() => new MySqlConnection(ConnectionString);
}
Support SQLite
- using MySqlConnector
dotnet add package Microsoft.Data.Sqlite --version 8.0.6
- new file
MySqlProvider
and inheritanceVitProvider
internal class SqliteProvider : VitProvider
{
public SqliteProvider(string connectionString) : base(connectionString)
{
}
protected override DbConnection Connection() => new SqliteConnection(ConnectionString);
}
Support Linq
- Context file
internal class MyContext : VitContext
{
public MyContext(IVitProvider provider) : base(provider)
{
MapTable<Customer>("Customers");
}
public VitSet<Customer> Customers { get; set; } = default!;
}
- Customer.cs
class Customer
{
public int Id { get; set; }
public string Name { get; set; } = "";
public string Email { get; set; } = "";
public string Address { get; set; } = "";
}
- Program.cs
var context = new MyContext(new VitProviderBeta("Data Source=.;Initial Catalog=TestDB;MultipleActiveResultSets=True;Integrated Security=True;"));
var query = from data in context.Customers select data;
foreach (var name in query)
{
Console.WriteLine(name.Id);
}
- Now, you can execute mysql.
Get Parameters Of Stored Procedure And Mapping Type
var vitParams = db.StoredParams("[dbo].[SYS_ReportParams]");
foreach (var item in vitParams)
{
var type = item.Type.GetTypeMap(); // mapping SqlDbType to Type
var defaultValue = type.GetDefaultValue(); // get default value of type
Console.WriteLine($"Type:{type}, ValueDefault:{defaultValue}");
}
Solutions For DynamicData
// Execute stored procedures without regard to parameters
var dataStored = db.ExecuteTable("[Login]", new("Username","Password", true));
// Execute stored procedures without regard to parameters but with paramsout
var paramsAuto = db.GetProcedureParams("[SYS_ReportParams]").ToVitParamsAuto();
var dataStored1 = db.StoredTable("[SYS_ReportParams]", paramsAuto.In, paramsAuto.Out);
Solutions for multiple results
If you have a "stored procedure" that returns multiple results like this, you can implement the method as shown below:
CREATE PROCEDURE [dbo].[RP_DM_MAU]
@pUID int = 0,
@pLang nvarchar(5) = 'vi',
@pTest NVARCHAR(max) = 'hehehe' OUT,
@pTest1 NVARCHAR(max) = 'hahaha' OUT
AS
select @pUID uid, @pLang lang
select 'Test1' Test1, 'Test2' Test2, 'Test3' Test3, 'Test4' Test4, 'Test5' Test5
select @pTest outTest, @pTest1 outTest1
return 0
GO
Currently, with "stored procedures" that return multiple results, "Vitado" has not found a simple and effective solution, so it has not implemented any official solution yet. But "Vitado" still provides some basic methods for you to implement those functions yourself.
public class CustomProvider : VitProvider, ICustomProvider
{
public CustomProvider(string connectionString) : base(connectionString)
{
}
public bool IsStoredProcedure(string query) => !query.Contains(' ');
//Get multiple rusults with "List<DataTable>"
public List<DataTable> ExecuteTables(string query) => BaseExecute(query, FuncExecuteTables);
public List<DataTable> ExecuteTables(string query, VitParams paramsIn) => BaseExecute(query, paramsIn, FuncExecuteTables);
public VitParamOutDataResult<List<DataTable>> ExecuteTables(string query, VitParams paramsIn, VitParamsOut paramsOut) => BaseExecute(query, paramsIn, paramsOut, FuncExecuteTables);
public Task<List<DataTable>> ExecuteTablesAsync(string query) => BaseExecute(query, FuncExecuteTablesAsync);
public Task<List<DataTable>> ExecuteTablesAsync(string query, VitParams paramsIn) => BaseExecute(query, paramsIn, FuncExecuteTablesAsync);
public Task<VitParamOutDataResult<List<DataTable>>> ExecuteTablesAsync(string query, VitParams paramsIn, VitParamsOut paramsOut) => BaseExecute(query, paramsIn, paramsOut, FuncExecuteTablesAsync);
//Get multiple rusults with "DbMultiResultsModel"
public T ExecuteMultiResults<T>(string query) where T : new()
{
if (typeof(T) == typeof(List<DataTable>))
{
return (T)(object)BaseExecute(query, FuncExecuteTables);
}
else if (typeof(T).IsSubclassOf(typeof(DbMultiResultsModel)))
{
var model = (DbMultiResultsModel)(object)new T();
if (model.ResultFields.Count < 1) return new();
return BaseExecute(query, command =>
{
var reader = command.ExecuteReader();
var indexField = 0;
do
{
model.ResultFields[indexField++].SetValue(reader);
} while (reader.NextResult());
return (T)(object)model;
});
}
return new();
}
}
"DbMultiResultsModel" is a base model class that provides "DbResultList" and "DbResult" management methods.
An important note is that all properties must be assigned "new()" by default.
internal class TesMultiResultModel : DbMultiResultsModel
{
public DbResultList<Mau> List { get; set; } = new(); //new() default
public DbResult<TestResult2> Test { get; set; } = new(); //new() default
}
public class Mau
{
public string Test1 { get; set; } = "";
public string Test2 { get; set; } = "";
public string Test3 { get; set; } = "";
public string Test4 { get; set; } = "";
public string Test5 { get; set; } = "";
}
public class TestResult2
{
[MapName("outTest")]
public string OutTest { get; set; } = "";
[MapName("outTest1")]
public string OutTest1 { get; set; } = "";
}
You can now seamlessly work with your database using this ADO.NET wrapper library, saving time and effort in your .NET applications.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net7.0 is compatible. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
-
net7.0
- Microsoft.Extensions.Configuration (>= 8.0.0)
- Microsoft.Extensions.DependencyInjection (>= 8.0.0)
- System.Data.SqlClient (>= 4.8.6)
- VTNET.Extensions (>= 7.1.7)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on VTNET.Vitado:
Package | Downloads |
---|---|
VTNET.Vitado.SqlServer
An SqlServer wrapper library |
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated | |
---|---|---|---|
7.2.0 | 128 | 8/9/2024 | |
7.2.0-beta.17 | 69 | 7/25/2024 | |
7.2.0-beta.16 | 44 | 7/24/2024 | |
7.2.0-beta.15 | 70 | 7/21/2024 | |
7.2.0-beta.14 | 64 | 7/16/2024 | |
7.2.0-beta.13 | 47 | 7/16/2024 | |
7.2.0-beta.12 | 53 | 7/16/2024 | |
7.2.0-beta.11 | 49 | 7/16/2024 | |
7.2.0-beta.10 | 52 | 7/15/2024 | |
7.2.0-beta.9 | 46 | 7/15/2024 | |
7.2.0-beta.8.1 | 57 | 7/15/2024 | |
7.2.0-beta.8 | 49 | 7/15/2024 | |
7.2.0-beta.7 | 49 | 7/15/2024 | |
7.2.0-beta.6 | 54 | 7/15/2024 | |
7.2.0-beta.5 | 47 | 7/14/2024 | |
7.2.0-beta.4 | 58 | 7/3/2024 | |
7.2.0-beta.3 | 54 | 7/1/2024 | |
7.2.0-beta.2 | 70 | 6/27/2024 | |
7.2.0-beta.1 | 47 | 6/26/2024 | |
7.1.0 | 107 | 5/7/2024 | |
7.0.2 | 152 | 2/28/2024 | |
7.0.1 | 169 | 2/21/2024 | |
7.0.0 | 132 | 2/21/2024 | |
2.0.10 | 122 | 1/19/2024 | |
2.0.9 | 128 | 1/18/2024 | |
2.0.8 | 144 | 1/15/2024 | |
2.0.7 | 190 | 11/27/2023 | |
2.0.6 | 145 | 11/3/2023 | |
2.0.5 | 152 | 10/27/2023 | |
2.0.4 | 138 | 10/27/2023 | |
2.0.3 | 143 | 10/27/2023 | |
2.0.2 | 143 | 10/27/2023 | |
2.0.1 | 173 | 10/25/2023 | |
2.0.0 | 164 | 10/12/2023 | |
1.1.3 | 174 | 9/27/2023 | |
1.1.2 | 147 | 9/20/2023 | |
1.1.1 | 166 | 9/13/2023 | |
1.1.0 | 173 | 9/13/2023 | |
1.0.15 | 170 | 9/12/2023 | |
1.0.14 | 174 | 9/12/2023 | |
1.0.13 | 175 | 9/8/2023 | |
1.0.12 | 178 | 8/25/2023 | |
1.0.11 | 171 | 8/11/2023 | |
1.0.10 | 182 | 8/10/2023 | |
1.0.9 | 169 | 8/9/2023 | |
1.0.8 | 171 | 8/9/2023 | |
1.0.7 | 170 | 8/9/2023 | |
1.0.6 | 183 | 8/4/2023 | |
1.0.5 | 181 | 8/3/2023 | |
1.0.4 | 176 | 8/3/2023 | |
1.0.3 | 176 | 8/3/2023 | |
1.0.2 | 171 | 8/3/2023 | |
1.0.1 | 180 | 8/2/2023 | |
1.0.0 | 181 | 8/2/2023 |