EDK4Net2 4.1.0
dotnet add package EDK4Net2 --version 4.1.0
NuGet\Install-Package EDK4Net2 -Version 4.1.0
<PackageReference Include="EDK4Net2" Version="4.1.0" />
<PackageVersion Include="EDK4Net2" Version="4.1.0" />
<PackageReference Include="EDK4Net2" />
paket add EDK4Net2 --version 4.1.0
#r "nuget: EDK4Net2, 4.1.0"
#:package EDK4Net2@4.1.0
#addin nuget:?package=EDK4Net2&version=4.1.0
#tool nuget:?package=EDK4Net2&version=4.1.0
EDK4Net2
EDK4Net2 is a framework designed to simplify the development of applications and libraries in C# / VB.NET, targeting .NET 10.0.
💡 Tip: Instead of writing classes by hand, use the EDK4Net Code Generator to generate them automatically from your database schema.
Features
- ORM – Active Record pattern via
BusinessObject<T>with automatic change tracking (IsNew,IsDirty,IsDeleted) - Query Language – LINQ-style fluent queries and a Classic SQL-like engine, both always available
- Validation – Imperative
CheckRules()/CheckDeleteRules()override withBrokenRuleException - Transactions (CNWrapper) – Atomic multi-object, multi-database transactions managed automatically by
Save() - Auditing – Per-property change recording with old/new values, user ID, and timestamp
- Object Locking – Pessimistic record locking (
LockExclusive/RemoveLock) for multi-user environments - Logging – File-based logger with email delivery, buffering and
Microsoft.Extensions.Loggingintegration - Code Generator – Windows WPF tool that generates all
BusinessObject<T>classes from your DB schema
Supported Databases
| Database | Provider |
|---|---|
| SQL Server | Microsoft.Data.SqlClient |
| MySQL | MySqlConnector |
Installation
dotnet add package EDK4Net2
Or via Package Manager Console in Visual Studio:
Install-Package EDK4Net2
Quick Start
1 – Configuration
Set the connection string and provider in Program.cs:
// Program.cs (.NET 10)
var builder = WebApplication.CreateBuilder(args);
EDK4NetConfig.DefaultCnString = builder.Configuration
.GetConnectionString("DefaultConnection");
EDK4NetConfig.DefaultDataProvider = DataProviderType.SqlServer;
EDK4NetConfig.EnableAudit = true;
// appsettings.json
{
"ConnectionStrings": {
"DefaultConnection": "Server=.;Database=MyDb;Trusted_Connection=True;"
}
}
2 – Define a Business Object
Every class inherits from BusinessObject<T>. Properties are automatically tracked.
using EDK4Net.Core;
using EDK4Net.Data;
public class Customer : BusinessObject<Customer>
{
[PrimaryKey]
public int CustomerId { get; set; }
public string FirstName { get; set; } = "";
public string LastName { get; set; } = "";
public string Email { get; set; } = "";
public bool IsActive { get; set; } = true;
// Factory methods called by the DataPortal
public static Customer GetObject(int id)
=> DataPortal.Fetch<Customer>(id);
public static Customer NewObject()
=> DataPortal.Create<Customer>();
}
// Collection class
public class CustomerCollection : SortableCollectionBase<Customer>
{
public static CustomerCollection GetCollection()
=> DataPortal.FetchCollection<CustomerCollection, Customer>();
}
3 – CRUD Operations
// --- CREATE ---
var customer = Customer.NewObject();
customer.FirstName = "Mario";
customer.LastName = "Rossi";
customer.Email = "mario.rossi@example.com";
if (customer.IsValid)
customer.Save(); // automatic INSERT
Console.WriteLine($"Created with ID: {customer.CustomerId}");
// --- READ ---
var single = Customer.GetObject(1);
Console.WriteLine($"{single.FirstName} {single.LastName}");
var all = CustomerCollection.GetCollection();
Console.WriteLine($"Total customers: {all.Count}");
// --- UPDATE ---
single.Email = "new@example.com";
Console.WriteLine($"Modified: {single.IsDirty}"); // true
single.Save(); // automatic UPDATE
// --- DELETE ---
single.Delete();
single.Save(); // automatic DELETE
4 – Validation Rules
Override CheckRules() to define save conditions and CheckDeleteRules() for delete conditions.
Save() calls CheckRules() automatically and throws BrokenRuleException on violations.
public class Customer : BusinessObject<Customer>
{
// ... properties ...
protected override void CheckRules()
{
if (string.IsNullOrEmpty(FirstName))
BrokenRules.Add(new BrokenRule(this,
"First name is required", FirstName));
if (LastName?.Length > 50)
BrokenRules.Add(new BrokenRule(this,
"Last name cannot exceed 50 characters", LastName));
}
protected override void CheckDeleteRules()
{
if (Orders.Count > 0)
BrokenRules.Add(new BrokenRule(this,
"Cannot delete: associated orders exist", Orders.Count));
}
}
// Usage
try
{
customer.Save();
}
catch (BrokenRuleException ex)
{
foreach (var rule in ex.BrokenRules)
Console.WriteLine(rule.RuleName);
// Output: "First name is required"
}
5 – Transactions (CNWrapper)
CNWrapper is the framework's internal connection and transaction coordinator — never instantiated directly.
It is created and managed automatically by Save(). All objects involved are committed together or rolled back atomically.
It also supports multi-database scenarios: objects on different databases are coordinated in the same atomic transaction.
public class Order : BusinessObject<Order>
{
// PreSaveMethod — called before the DB write; prepare related objects
protected override void PreSaveMethod(CNWrapper cnWrapper)
{
if (IsDeleted)
{
foreach (var item in Items)
{
item.Delete();
CurrentCNWrapper.AddObject(item);
}
}
}
// PostSaveMethod — called after the parent write, before commit; save children
protected override void PostSaveMethod(CNWrapper cnWrapper, SavingType saveMethod)
{
if (saveMethod == SavingType.Insert)
{
foreach (var note in newNotes)
{
note.OrderId = OrderId; // propagate the new parent ID
note.Save(cnWrapper); // same transaction as the parent
}
newCommissions.Save(cnWrapper);
}
Lines.Save(cnWrapper); // always save lines in the same transaction
}
// AfterSaveMethod — called after commit; CNWrapper is already closed
protected override void AfterSaveMethod(bool saved, SavingType saveMethod)
{
if (saved)
Cache.Invalidate(this);
}
// Add a related object to the current transaction from a business method
public void Approve()
{
relatedAsset.TotalAvailable += Amount;
CurrentCNWrapper.AddObject(relatedAsset);
Save();
}
}
6 – Query Language
Two query engines are always available.
// --- LINQ Query (recommended) ---
// Simple filter + ordering + pagination
var query = Order.Query()
.Where(o => o.Status == "Active")
.OrderByDescending(o => o.OrderDate)
.Take(20)
.ToSelectQuery();
var orders = new OrderCollection();
orders.GetBySelectQuery(query);
// OR conditions
var query2 = Order.Query()
.Where(o => o.Status == "Pending")
.WhereOr(o => o.Status == "Processing")
.ToSelectQuery();
// Join between entities with filters on both
var query3 = Order.Query()
.Join<OrderLine, int>(o => o.Id, l => l.OrderId)
.Where(o => o.CustomerId == 42)
.Where<OrderLine>(l => l.Quantity > 0)
.Distinct()
.ToSelectQuery();
// Pagination
var page = Order.Query()
.Where(o => o.Status == "Active")
.OrderBy(o => o.Id)
.Skip(20).Take(10)
.ToSelectQuery();
// ToSelectQuery() converts to the classic engine:
// use with GetBySelectQuery() to load collections,
// or with GetCustomQueryDV() to get a DataView.
// --- Classic QueryLanguage (always available) ---
// More complete, SQL-like syntax.
// Supports SelectQuery, CustomQuery, DeleteQuery,
// aggregate functions (TOP, COUNT, MAX, MIN, SUM, AVG)
// and direct access to Properties and Operators.
7 – EDK4Net Code Generator
The EDK4Net Code Generator is a Windows WPF (.NET 10) application that automatically generates
all BusinessObject<T> classes and their collections directly from your database schema (SQL Server or MySQL),
eliminating all boilerplate code. It will soon also be available as a Visual Studio add-on.
Typical workflow:
- Configure the DB connection (DB Options)
- Reload the schema (Reload)
- Customise class names, namespaces, and property types
- Generate the code (Generate Code) —
.csfiles are written to disk - Add your business logic in the separate
partialfiles
// File BASE (auto-generated — never edit this file)
[Serializable]
[ObjectMetaData(TableName = "Customers")]
public partial class Customer : BusinessObject<Customer>
{
[PrimaryKey, AutoKey]
public int CustomerId { get; set; }
public string FirstName { get; set; } = "";
public string LastName { get; set; } = "";
public string Email { get; set; } = "";
public bool IsActive { get; set; }
protected override object GetIdValue() => CustomerId;
protected override string GetDefaultCNString()
=> EDK4NetConfig.DefaultCnString;
// ... FetchMethod, InsertMethod, UpdateMethod, DeleteMethod generated here
}
// File PARTIAL (your logic — never overwritten by the generator)
public partial class Customer
{
protected override void CheckRules()
{
if (string.IsNullOrEmpty(FirstName))
BrokenRules.Add(new BrokenRule(this,
"First name is required", FirstName));
}
public static Customer GetCustomer(int id)
{
var e = CreateExampleObject();
e.CustomerId = id;
return GetByExample(e);
}
}
Key features:
- TreeView with table, class, or namespace view
- Live search in the tables panel
- Inline editing: class name, namespace, column type
- Configurable
[Obsolete]attribute per column - DB schema comparison (detects added/removed tables)
- Import of legacy projects (
.e4ncg→.e4nproj) - Coming soon: Visual Studio add-on
8 – Auditing
Enable auditing on a class by overriding AuditEnabled() and KindOfAudit().
Every property change is automatically recorded as a DbChange entry (old value, new value, user, timestamp).
public class Product : BusinessObject<Product>
{
protected override bool AuditEnabled() => true;
protected override AuditKind KindOfAudit()
=> AuditKind.All; // Insert + Update + Delete
}
// Read the change history
var product = Product.GetObject(1);
var history = product.AuditHistory;
foreach (var change in history)
{
Console.WriteLine($"{change.ChangeDate}: {change.UserName}");
foreach (var prop in change.Properties)
Console.WriteLine($" {prop.PropertyName}: {prop.OldValue} -> {prop.NewValue}");
}
9 – Object Locking
Pessimistic locking for multi-user environments. Locks are managed in the audit database.
var document = Document.GetObject(documentId);
if (document.IsLocked())
{
Console.WriteLine("Document is being edited by another user!");
return;
}
var lockReceipt = document.LockExclusive();
if (!string.IsNullOrEmpty(lockReceipt.Ticket))
{
try
{
document.Title = "New Title";
document.Save();
}
finally
{
document.RemoveLock(lockReceipt.Ticket);
}
}
10 – Logging
using EDK4Net.Log;
var log = Logger.NewLogger("MyComponent");
log.SubPath = "AppLogs\\";
log.Logformat = Logger.LogFormat.Frequent;
log.WriteLine("Operation completed.");
log.Save();
To integrate with Microsoft.Extensions.Logging:
// Program.cs
Logger.ConfigureLoggerFactory(loggerFactory);
Configuration Reference
| Key | Type | Default | Description |
|---|---|---|---|
DefaultCnString |
string | — | Default database connection string |
DefaultDataProvider |
SqlServer | MySql |
SqlServer |
Database provider |
EnableAudit |
bool | false |
Enable automatic change auditing |
EnableAuthorizationRules |
bool | false |
Enable authorization rule checks |
DBLogging |
bool | false |
Log generated SQL statements to file |
LockDuration |
int (seconds) | 20 |
Duration of a pessimistic object lock |
CacheDuration |
int (minutes) | 20 |
In-memory object cache duration |
LongQueryTimeout |
int (seconds) | 120 |
Command timeout for long-running queries |
ReadOnly |
bool | false |
Prevent all write operations |
logPath |
string | app dir | Base path for log files |
EnvironmentType |
Production | Test | Demo |
Production |
Runtime environment tag |
DebugMode |
bool | false |
Enable verbose debug output |
Requirements
- .NET 10.0
- SQL Server 2012+ or MySQL 5.7+
Links
- 📖 Documentation & Code Generator: http://edk4net.edika.net
- 📦 NuGet: https://www.nuget.org/packages/EDK4Net2
License
Copyright © Edika 2003–2025. All rights reserved.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- BouncyCastle.Cryptography (>= 2.6.2)
- Microsoft.Data.SqlClient (>= 7.0.0)
- MySqlConnector (>= 2.5.0)
- System.Configuration.ConfigurationManager (>= 10.0.6)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 4.1.0 | 54 | 4/18/2026 |
Net 10 public release