Вот мое однолинейное решение
(вызов одной строки, реализация немного больше)
Я взял код у @elbweb и адаптировал его для своих целей. В моем случае я выполнял синтаксический анализ файлов EDI, некоторые из которых имели 15 различных уровней иерархии, и я не хотел явно указывать все 15 различных типов - я хотел, чтобы одна строка работала для всех типов сущностей.
Это немного по-другому, но теперь звонить безболезненно. Это определенно сказывается на производительности, но для меня это приемлемо. По сути, поместите это внутри вашего класса DbContext, а затем вызовите его вручную в одну строку (или вы можете автоматически вызвать его, переопределив SaveChanges для его вызова).
Код в вашем DbContext:
public class MyContext : DbContext
{
...
public void TruncateAllStringsOnAllEntitiesToDbSize()
{
var objectContext = ((IObjectContextAdapter) this).ObjectContext;
var stringMaxLengthsFromEdmx =
objectContext.MetadataWorkspace
.GetItems(DataSpace.CSpace)
.Where(m => m.BuiltInTypeKind == BuiltInTypeKind.EntityType)
.SelectMany(meta => ((EntityType) meta).Properties
.Where(p => p.TypeUsage.EdmType.Name == "String"))
.Select(d => new
{
MaxLength = d.TypeUsage.Facets["MaxLength"].Value,
PropName = d.Name,
EntityName = d.DeclaringType.Name
})
.Where(d => d.MaxLength is int)
.Select(d => new {d.PropName, d.EntityName, MaxLength = Convert.ToInt32(d.MaxLength)})
.ToList();
var pendingEntities = ChangeTracker.Entries().Where(e => e.State == EntityState.Added || e.State == EntityState.Modified).Select(x => x.Entity).ToList();
foreach (var entityObject in pendingEntities)
{
var relevantFields = stringMaxLengthsFromEdmx.Where(d => d.EntityName == entityObject.GetType().Name).ToList();
foreach (var maxLengthString in relevantFields)
{
var prop = entityObject.GetType().GetProperty(maxLengthString.PropName);
if (prop == null) continue;
var currentValue = prop.GetValue(entityObject);
var propAsString = currentValue as string;
if (propAsString != null && propAsString.Length > maxLengthString.MaxLength)
{
prop.SetValue(entityObject, propAsString.Substring(0, maxLengthString.MaxLength));
}
}
}
}
}
Потребление
try
{
innerContext.TruncateAllStringsOnAllEntitiesToDbSize();
innerContext.SaveChanges();
}
catch (DbEntityValidationException e)
{
foreach (var err in e.EntityValidationErrors)
{
log.Write($"Entity Validation Errors: {string.Join("\r\n", err.ValidationErrors.Select(v => v.PropertyName + "-" + v.ErrorMessage).ToArray())}");
}
throw;
}
Перед этим кодом SaveChanges
вызовет перехват в моем примере выше, когда вы попытаетесь вставить слишком большую строку. После добавления строки TruncateAllStringsOnAllEntitiesToDbSize
теперь она отлично работает! Я уверен, что есть некоторые оптимизации, которые могут пойти на это, так что, пожалуйста, критикуйте / помогайте! : -)
Примечание: я пробовал это только на EF 6.1.3