RossWright.MetalCore.Data 2026.1.1

dotnet add package RossWright.MetalCore.Data --version 2026.1.1
                    
NuGet\Install-Package RossWright.MetalCore.Data -Version 2026.1.1
                    
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="RossWright.MetalCore.Data" Version="2026.1.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="RossWright.MetalCore.Data" Version="2026.1.1" />
                    
Directory.Packages.props
<PackageReference Include="RossWright.MetalCore.Data" />
                    
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 RossWright.MetalCore.Data --version 2026.1.1
                    
#r "nuget: RossWright.MetalCore.Data, 2026.1.1"
                    
#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 RossWright.MetalCore.Data@2026.1.1
                    
#: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=RossWright.MetalCore.Data&version=2026.1.1
                    
Install as a Cake Addin
#tool nuget:?package=RossWright.MetalCore.Data&version=2026.1.1
                    
Install as a Cake Tool

Ross Wright's Metal Core Data Library

Copyright (c) 2023-2026 Pross Co.

Table of Contents


Entity Framework Extensions

Database Context

DbContextExtensions adds three utility methods to any DbContext that targets a relational database.

Method Description
DatabaseExists() Returns true if the underlying relational database has been created
CheckForChangesToAny<T>() Returns true if the change tracker holds pending changes for entity type T
Obliterate() Drops all FK constraints, tables, and stored procedures — SQL Server only; intended for test teardown

Obliterate() is destructive. It is designed for integration test teardown where a fresh schema is required between runs. Do not call it in production code.


SaveChanges with FK Errors

DbContextExtensions.SaveChangesAsyncWithFkErrors wraps SaveChangesAsync and provides structured handling for foreign key constraint violations. When EF throws a DbUpdateException caused by an FK constraint, the callback receives the parsed constraint name rather than requiring you to parse the exception message yourself.

await context.SaveChangesAsyncWithFkErrors(report =>
    throw new InvalidOperationException($"Cannot delete: referenced by '{report.ConstraintName}'"));
Method Description
SaveChangesAsyncWithFkErrors(onError) Calls SaveChangesAsync; on FK violation invokes onError with a ForeignKeyErrorReport; always re-throws the original exception

ForeignKeyErrorReport properties:

Property Type Description
EntityName string Name of the entity type involved in the violation
ConstraintName string? Database constraint name parsed from the exception message
Values Dictionary<string, object?> Current property values of the violating entity, keyed by property name

RefreshTable

RefreshTableExtensions.RefreshTable synchronizes a DbSet<DBENTITY> against an incoming collection of INENTITY objects in a single call, performing the insert/update/delete logic automatically. It returns an IRefreshResult reporting how many records were added, updated, and deleted.

var result = await context.Users.RefreshTable(incomingUsers);
// result.Adds, result.Updates, result.Deletes

By default, records absent from the incoming data are not deleted. Pass deleteSourceEntities: true to enable removal of absent records.

Record matching — overloads constrained to IHasId match by Guid Id. Overloads without that constraint accept a custom Func<DBENTITY, INENTITY, bool> isSame predicate.

Entity copying — by default, matching members are copied using CopyTo. Pass a custom Action<DBENTITY, INENTITY> update delegate to control exactly which fields are updated.

Data fetching — by default, ToListAsync() loads the current set. Pass a custom Func<DbSet<DBENTITY>, Task<List<DBENTITY>>> fetchOldData delegate to apply filters (e.g. restrict to a specific parent record).

The seven overloads cover combinations of these three axes:

Overload Match Update Fetch
(dbSet, newData, deleteSourceEntities?) IHasId auto default
(dbSet, newData, Action update, deleteSourceEntities?) IHasId custom default
(dbSet, fetchOldData, newData, Action update, deleteSourceEntities?) IHasId custom custom
(dbSet, newData, Func isSame, deleteSourceEntities?) custom auto default
(dbSet, newData, Func isSame, Action update, deleteSourceEntities?) custom custom default
(dbSet, fetchOldData, newData, Func isSame, Action update, deleteSourceEntities?) custom custom custom
(dbSet, fetchOldData, newData, Func isSame, Func add, Action update, deleteSourceEntities) custom custom custom + custom add

IHasId is a core MetalCore contract (RossWright namespace) that requires a Guid Id property. Most database entity base classes implement it.

IRefreshResult
Property Description
Adds Number of entities inserted
Updates Number of entities updated
Deletes Number of entities deleted

Database Timing Interceptor

IDatabaseTimingInterceptor accumulates the total EF command execution time for the current DI scope, enabling per-request database timing without external tooling.

Register in Program.cs and attach to your DbContext options:

// Program.cs
services.AddDatabaseTimingInterceptor();
services.AddDbContext<AppDbContext>((sp, opts) =>
    opts.UseSqlServer(connectionString)
        .UseDatabaseTimingInterceptor(sp));

// Inject IDatabaseTimingInterceptor anywhere in the same scope
var ms = timingInterceptor.RunTimeInMilliseconds;
Method / Member Description
AddDatabaseTimingInterceptor(IServiceCollection) Registers IDatabaseTimingInterceptor as a scoped EF interceptor
UseDatabaseTimingInterceptor(DbContextOptionsBuilder, IServiceProvider) Attaches the interceptor to a DbContext options builder
IDatabaseTimingInterceptor.RunTimeInMilliseconds Cumulative EF command execution time for the current scope in milliseconds

Registration lifetime: AddDatabaseTimingInterceptor registers the interceptor as scoped, which is required for per-request timing to work correctly. Do not register IDatabaseTimingInterceptor as a singleton — doing so will cause timing to accumulate across all requests rather than resetting per scope.


GeoCoder

IGeoCoderService provides a single method that resolves a US postal code or "City, State" string to a latitude/longitude coordinate pair.

Offline lookup only. The bundled GeoCoderService uses an embedded data file — it does not contact any external API. Only US postal codes and "City, State" strings are supported. Unrecognized inputs throw MetalCoreException.

var coords = geoCoderService.GetCoordinates("90210");        // zip code
var coords = geoCoderService.GetCoordinates("Beverly Hills, CA"); // City, State
// coords.Lat, coords.Lng

Register with AddGeoCoderService():

services.AddGeoCoderService();

LatLong

LatLong is a value struct holding a latitude and longitude. It provides two utility methods for geographic calculations:

Member Description
Lat Latitude in decimal degrees
Lng Longitude in decimal degrees
DistanceTo(double lat, double lng) Returns the distance in miles to the given coordinate using the Haversine formula, rounded to 2 decimal places
CalcBound(double distance) Returns a bounding box (LatLong min, LatLong max) for the given radius in miles

Service Reference

Type / Method Description
IGeoCoderService.GetCoordinates(string address) Resolves an address or place string to a LatLong
AddGeoCoderService(IServiceCollection) Registers IGeoCoderService as a singleton

Installation

dotnet add package RossWright.MetalCore.Data

Or add directly to your project file:

<PackageReference Include="RossWright.MetalCore.Data" Version="*" />

See Also

Package Purpose
RossWright.MetalCore Core extensions, utilities, options builders, load logging, exceptions, signing
RossWright.MetalCore.Blazor Blazor WASM utilities: local storage, JS script loader, host builder extensions
RossWright.MetalCore.Server ASP.NET Core messaging contracts, SMTP email service
RossWright.MetalCore.Populi Zero-dependency test-data generator: names, addresses, emails, coordinates, dates, prices, and lorem ipsum

License

All Ross Wright Metal Libraries including this one are licensed under Apache License 2.0 with Commons Clause.

You are free to:

  • Use the libraries in any project (personal or commercial)
  • Modify them
  • Include them in products or services you sell

You may not:

  • Sell the libraries themselves (or any product/service whose primary value comes from the libraries)
  • Repackage them with minimal changes and sell them as your own standalone product

Full legal text: LICENSE.md

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  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 is compatible.  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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on RossWright.MetalCore.Data:

Package Downloads
RossWright.MetalCommand.Data

Licensed under Apache 2.0 with Commons Clause — free to use in commercial products, but you may not sell the Metal Libraries themselves or any product whose primary value comes from them.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2026.1.1 150 5/17/2026
2026.1.0 149 5/14/2026
2026.0.0 139 4/26/2026
10.0.12 160 3/10/2026 10.0.12 is deprecated because it is no longer maintained.
10.0.11 156 2/23/2026 10.0.11 is deprecated because it is no longer maintained.
10.0.10 150 2/16/2026 10.0.10 is deprecated because it is no longer maintained.
10.0.9 143 2/16/2026 10.0.9 is deprecated because it is no longer maintained.
10.0.8 146 2/16/2026 10.0.8 is deprecated because it is no longer maintained.
10.0.7 162 2/12/2026 10.0.7 is deprecated because it is no longer maintained.
10.0.6 144 2/12/2026 10.0.6 is deprecated because it is no longer maintained.
10.0.5 151 1/26/2026 10.0.5 is deprecated because it is no longer maintained.
10.0.4 158 1/24/2026 10.0.4 is deprecated because it is no longer maintained.
10.0.3 166 1/16/2026 10.0.3 is deprecated because it is no longer maintained.
10.0.2 163 1/11/2026 10.0.2 is deprecated because it is no longer maintained.
10.0.1 166 1/10/2026 10.0.1 is deprecated because it is no longer maintained.
10.0.0 163 1/9/2026 10.0.0 is deprecated because it is no longer maintained.
8.5.3 181 1/11/2026 8.5.3 is deprecated because it is no longer maintained.
8.5.2 189 1/11/2026 8.5.2 is deprecated because it is no longer maintained.
8.5.1 181 1/10/2026 8.5.1 is deprecated because it is no longer maintained.
8.5.0 179 1/10/2026 8.5.0 is deprecated because it is no longer maintained.
Loading failed

[2026.1.1] - 5/17/2026
- Minor Fixes, additional Unit Tests and documentation.

[2026.1.0] - 5/13/2026
- Minor Fixes, additional Unit Tests and documentation.

[2026.0.0] - 4/26/2026
- Initial public release

** Prior versions released of this library were private and not intended for public use. Use version 2026.0.0 or later.**