DataMagic.Abstractions 1.2.0

dotnet add package DataMagic.Abstractions --version 1.2.0
                    
NuGet\Install-Package DataMagic.Abstractions -Version 1.2.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="DataMagic.Abstractions" Version="1.2.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="DataMagic.Abstractions" Version="1.2.0" />
                    
Directory.Packages.props
<PackageReference Include="DataMagic.Abstractions" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add DataMagic.Abstractions --version 1.2.0
                    
#r "nuget: DataMagic.Abstractions, 1.2.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package DataMagic.Abstractions@1.2.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=DataMagic.Abstractions&version=1.2.0
                    
Install as a Cake Addin
#tool nuget:?package=DataMagic.Abstractions&version=1.2.0
                    
Install as a Cake Tool

DataMagic.Abstractions

DataMagic.Abstractions is a small .NET Standard 2.1 library of shared contracts and models for querying and updating data: filters, sorting, paging, search results, entity interfaces and partial updates.

It contains no query logic and no database driver. Filters and pagers only describe a request; your data access layer (EF Core, Dapper, MongoDB, ...) reads them and builds the actual query.

Installation

dotnet add package DataMagic.Abstractions

Contents

Namespace Contains
DataMagic.Abstractions.Constants PagerKinds, SortDirections, DatabaseTypes
DataMagic.Abstractions.Constants.Operators Comparison operators and text filter modes
DataMagic.Abstractions.Interfaces IPager, ISearchResult<T>, IDatabaseOptions, IUpdatableProperty<T>, IImmutableEntity<TId, TTime>, IMutableEntity<TId, TTime>
DataMagic.Abstractions.Models Date, SearchResult<T>, SortableProperty, UpdatableProperty<T>
DataMagic.Abstractions.Models.Filters Filter models
DataMagic.Abstractions.Models.Pagers IPager implementations
DataMagic.Abstractions.Models.Databases IDatabaseOptions implementations

Constants

PagerKinds

String values that identify a pager type. Each pager exposes one through IPager.Kind, so you can tell pagers apart after they cross an API boundary.

Constant Value Used by
PagerKinds.Default "default" DefaultPager
PagerKinds.SkipLimit "skipLimit" SkipLimitPager
PagerKinds.Index "index" IndexPager

Enums

Enum Members Used by
SortDirections None, Ascending, Descending SortableProperty
DatabaseTypes Mongo, Postgresql, Redis, SqlServer IDatabaseOptions
NumericComparisonOperators SmallerThan, SmallerThanEqualTo, Equal, GreaterThanEqualTo, GreaterThan, None NumericFilter<T>
DateComparisonOperators SmallerThan, SmallerThanEqualTo, Equal, GreaterThanEqualTo, GreaterThan, None DateFilter
DateTimeComparisonOperators SmallerThan, SmallerThanEqualTo, Equal, GreaterThanEqualTo, GreaterThan DateTimeFilter
TextFilterModes Equal, EqualIgnoreCase, Contains, StartWith, EndWith, None TextFilter

An operator left unset takes the enum's first member. For the numeric, date and date-time operators that is SmallerThan, not None, so always set the operator explicitly.

Filters

Each filter pairs a value with the operator to apply. Range filters combine two filters into a lower and an upper bound.

Class Responsibility
TextFilter Matches a string Value using a Mode
NumericFilter<T> Compares a numeric Value using an Operator
NumericRangeFilter<TFrom, TTo> Numeric range with From and To
DateFilter Compares a Date value using an Operator
DateRangeFilter Date range with optional From and To
DateTimeFilter Compares a DateTime? value using an Operator
DateTimeRangeFilter Date-time range with required constructor arguments from and to
using DataMagic.Abstractions.Constants.Operators;
using DataMagic.Abstractions.Models;
using DataMagic.Abstractions.Models.Filters;

var name = new TextFilter { Value = "linh", Mode = TextFilterModes.Contains };

var price = new NumericRangeFilter<decimal, decimal>(
    new NumericFilter<decimal>(10m, NumericComparisonOperators.GreaterThanEqualTo),
    new NumericFilter<decimal>(50m, NumericComparisonOperators.SmallerThan));

var birthday = new DateRangeFilter
{
    From = new DateFilter
    {
        Value = new Date(2000, 1, 1),
        Operator = DateComparisonOperators.GreaterThanEqualTo
    }
};

var createdTime = new DateTimeRangeFilter(
    new DateTimeFilter(new DateTime(2026, 1, 1), DateTimeComparisonOperators.GreaterThanEqualTo),
    new DateTimeFilter("2026-02-01", DateTimeComparisonOperators.SmallerThan));

NumericFilter<T>.ValidNumericTypes() returns the supported numeric types and their nullable forms. The constructor does not currently reject other types, so check T yourself if it comes from outside your code.

Your query layer applies the filter, for example:

if (name.Value != null && name.Mode == TextFilterModes.Contains)
    query = query.Where(x => x.Name.Contains(name.Value));

Sorting

SortableProperty names a property and the direction to sort it in.

using DataMagic.Abstractions.Constants;
using DataMagic.Abstractions.Models;

var sort = new SortableProperty { Name = "createdTime", Direction = SortDirections.Descending };

Paging

IPager tells your data access layer what to fetch:

Member Responsibility
Kind Pager type, one of PagerKinds
ShouldItemsQueried() Whether to fetch the items. Always false when the page size is below 1
ShouldItemsCounted() Whether to count all matching records
GetSkippedRecords() Number of records to skip
GetTotalRecords() Number of records to take, which is the page size rather than the total count
Class Input Skipped records
DefaultPager 1-based page, totalRecords (page - 1) * totalRecords
IndexPager 0-based pageIndex, totalRecords pageIndex * totalRecords
SkipLimitPager skippedRecords, totalRecords skippedRecords

All pagers throw ArgumentException on out-of-range input.

using DataMagic.Abstractions.Interfaces;
using DataMagic.Abstractions.Models.Pagers;

IPager firstPage = new DefaultPager(1, 20);
IPager secondPage = new IndexPager(1, 20, true, true);
IPager offset = new SkipLimitPager(40, 20);

// Count only, without fetching items.
IPager countOnly = new DefaultPager(1, 20, false, true);

DefaultPager and SkipLimitPager query and count by default. IndexPager does neither unless you say so: new IndexPager(0, 20) returns false from both ShouldItemsQueried() and ShouldItemsCounted(), so pass both flags as shown above.

Use the pager in your query, for example:

var totalRecords = pager.ShouldItemsCounted() ? await query.CountAsync() : 0;

var items = pager.ShouldItemsQueried()
    ? await query.Skip((int)pager.GetSkippedRecords()).Take((int)pager.GetTotalRecords()).ToListAsync()
    : new List<Product>();

Search results

ISearchResult<T> and its implementation SearchResult<T> hold one page of Items and the TotalRecords matching the query. A null item sequence becomes an empty array.

using DataMagic.Abstractions.Interfaces;
using DataMagic.Abstractions.Models;

ISearchResult<Product> result = new SearchResult<Product>(items, totalRecords);

var product = result.FirstOrDefault();
Method When there are no items
First(), FirstAsync() Throws InvalidOperationException
FirstOrDefault(), FirstOrDefaultAsync() Returns default

Entities

Interface Responsibility
IImmutableEntity<TId, TTime> Entity that never changes after creation. Exposes read-only Id and CreatedTime
IMutableEntity<TId, TTime> Extends IImmutableEntity<TId, TTime> with a settable UpdatedTime

TId and TTime are generic, so you choose the key and time types.

using DataMagic.Abstractions.Interfaces;

public class AuditLog : IImmutableEntity<Guid, DateTime>
{
    public Guid Id { get; init; }

    public DateTime CreatedTime { get; init; }
}

public class Product : IMutableEntity<Guid, DateTime>
{
    public Guid Id { get; init; }

    public DateTime CreatedTime { get; init; }

    public DateTime UpdatedTime { get; set; }
}

The init accessor needs .NET 5 or later. On older targets use set instead.

UpdatedTime is declared as TTime?, but C# only makes that nullable when TTime is a reference type. With DateTime it is a plain DateTime, so an entity that was never updated holds default(DateTime) rather than null.

Partial updates

IUpdatableProperty<T> and its implementation UpdatableProperty<T> pair a Value with a HasModified flag. This separates "leave this field alone" from "set this field to null", which a plain nullable property cannot do.

using DataMagic.Abstractions.Models;

public class UpdateProductModel
{
    public UpdatableProperty<string?>? Description { get; set; }
}

var model = new UpdateProductModel
{
    Description = new UpdatableProperty<string?>(null, true)
};

if (model.Description?.HasModified == true)
    product.Description = model.Description.Value;

Database options

IDatabaseOptions describes how to reach a database with separate fields instead of a connection string. Your data access layer builds the driver's connection settings from them.

Member Responsibility
Type Database type, one of DatabaseTypes
Host Host name or IP address. Defaults to localhost
Port Server port. Defaults to the database's standard port
Username, Password Credentials. Leave null when the server has no authentication
UseTls Whether to encrypt the connection. Defaults to false
Class Default port Extra members
MongoDatabaseOptions 27017 DatabaseName, AuthenticationDatabase (defaults to admin), ReplicaSet
PostgresqlDatabaseOptions 5432 DatabaseName, Schema
RedisDatabaseOptions 6379 Database (logical database index, defaults to 0)
SqlServerDatabaseOptions 1433 DatabaseName, InstanceName, TrustServerCertificate

Each class implements IDatabaseOptions directly. To support another database, implement the interface yourself.

All members except Type are settable, so the classes bind from configuration:

{
  "Databases": {
    "Mongo": {
      "Host": "mongo.internal",
      "Username": "asset-service",
      "Password": "<from secret store>",
      "DatabaseName": "assets"
    }
  }
}
using DataMagic.Abstractions.Models.Databases;

var mongo = builder.Configuration.GetSection("Databases:Mongo").Get<MongoDatabaseOptions>()!;

Then map the fields to the driver, for example with MongoDB.Driver:

var settings = new MongoClientSettings
{
    Server = new MongoServerAddress(mongo.Host, mongo.Port),
    UseTls = mongo.UseTls,
    ReplicaSetName = mongo.ReplicaSet
};

if (mongo.Username != null)
    settings.Credential = MongoCredential.CreateCredential(
        mongo.AuthenticationDatabase, mongo.Username, mongo.Password);

var database = new MongoClient(settings).GetDatabase(mongo.DatabaseName);

Date

Date is a date without a time, intended for values received from a front end.

using DataMagic.Abstractions.Models;

var date = new Date(2026, 11, 2);

DateTime midnight = date.ToDateTime();
DateTime withTime = date.ToDateTime(14, 30, 0);

var isLater = date > new Date(2026, 1, 1);
var isSame = date.Equals(new Date(2026, 11, 2));
  • The constructor throws Exception for a year before 1753, or for an invalid month or day.
  • Derive from Date and override IsValidYear, IsValidMonth or IsValidDate to change the rules.
  • Use Equals to compare dates. The == and != operators currently overflow the stack and terminate the process.
  • >, >=, < and <= work but throw NullReferenceException if either side is null.
  • Date does not override GetHashCode, so do not use it as a dictionary key or in a HashSet.
  • Validation treats every fourth year as a leap year, so new Date(1900, 2, 29) is accepted and fails later when converted to a DateTime.
Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  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.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  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. 
.NET Core netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.1 is compatible. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETStandard 2.1

    • No dependencies.

NuGet packages (9)

Showing the top 5 NuGet packages that depend on DataMagic.Abstractions:

Package Downloads
DataMagic.MongoDatabase

Package Description

DataMagic.Apis.Abstractions

Package Description

ApiFeatures.Modules.Cores

Package Description

ApiFeatures.Mqtt.Apis

Package Description

IotVn.CoreFeatures.JsonConverters.Newtonsoft

Package Description

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.2.0 229 11/2/2026
1.1.0 99 11/2/2026
1.0.2 436 8/17/2026
1.0.1 991 10/28/2025