Skip to content

Instantly share code, notes, and snippets.

@abrari
Last active June 13, 2024 04:36
Show Gist options
  • Save abrari/dfe772db172f950e9f0d8acdd3982fbb to your computer and use it in GitHub Desktop.
Save abrari/dfe772db172f950e9f0d8acdd3982fbb to your computer and use it in GitHub Desktop.
EF Core Auto Truncate String to Maximum Length
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
namespace MyExtensions
{
public static class DbContextExtension
{
private static Dictionary<IProperty, int> _maxLengthMetadataCache;
private static Dictionary<IProperty, int> GetMaxLengthMetadata(this DbContext db)
{
if (_maxLengthMetadataCache == null)
{
_maxLengthMetadataCache = new Dictionary<IProperty, int>();
var entities = db.Model.GetEntityTypes();
foreach (var entityType in entities)
{
foreach (var property in entityType.GetProperties())
{
var annotation = property.GetAnnotations().FirstOrDefault(a => a.Name == "MaxLength");
if (annotation != null)
{
var maxLength = Convert.ToInt32(annotation.Value);
if (maxLength > 0)
{
_maxLengthMetadataCache[property] = maxLength;
}
}
}
}
}
return _maxLengthMetadataCache;
}
public static void AutoTruncateStringToMaxLength(this DbContext db)
{
var entries = db?.ChangeTracker?.Entries();
if (entries == null)
{
return;
}
var maxLengthMetadata = db.GetMaxLengthMetadata();
foreach (var entry in entries)
{
var propertyValues = entry.CurrentValues.Properties.Where(p=> p.ClrType == typeof(string));
foreach (var prop in propertyValues)
{
if (entry.CurrentValues[prop.Name] != null)
{
var stringValue = entry.CurrentValues[prop.Name].ToString();
if (maxLengthMetadata.ContainsKey(prop))
{
var maxLength = maxLengthMetadata[prop];
stringValue = TruncateString(stringValue, maxLength);
}
entry.CurrentValues[prop.Name] = stringValue;
}
}
}
}
private static string TruncateString(string value, int maxLength)
{
if (string.IsNullOrEmpty(value)) return value;
return value.Length <= maxLength ? value : value.Substring(0, maxLength);
}
}
}
using System.Threading;
using System.Threading.Tasks;
using MyExtensions;
namespace MyModels
{
public partial class MyDbContext
{
public override int SaveChanges()
{
this.AutoTruncateStringToMaxLength();
return base.SaveChanges();
}
public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = new CancellationToken())
{
this.AutoTruncateStringToMaxLength();
return base.SaveChangesAsync(cancellationToken);
}
public override int SaveChanges(bool acceptAllChangesOnSuccess)
{
this.AutoTruncateStringToMaxLength();
return base.SaveChanges(acceptAllChangesOnSuccess);
}
public override Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = new CancellationToken())
{
this.AutoTruncateStringToMaxLength();
return base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
}
}
}
@ppmBeebie
Copy link

That's great ... I use it in my .netframework 4.8 & ef-core

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment