Entity Framework 4.0 Automatically Truncate/Trim String Before Insert

后端 未结 5 875
日久生厌
日久生厌 2020-12-30 04:36

Suppose I have a table with the column Description, varchar(100). If try to insert a string with more than 100 characters, the insert will fail.

Is there a way in En

5条回答
  •  醉酒成梦
    2020-12-30 05:03

    Here's my One-Line Solution

    (invoking it is one line, the implementation is a little more)

    I took the code from @elbweb and adapted it for my purposes. In my case I was parsing EDI files, some of which had 15 different levels to the hierarchy and I didn't want to explicitly specify all 15 different types - I wanted a one-liner that worked for all entity types.

    It's a bit different but it's now painless to call. There is definitely a performance hit on this but it's acceptable for me. Essentially put this inside of your DbContext class and then it's a one-liner to manually call (or you can automatically call it by overriding SaveChanges to invoke it).

    Code in your 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));
                    }
                }
            }
        }
    }
    

    Consumption

    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;
    }
    

    Before this code, the SaveChanges would trigger the catch in my example above when you tried inserting a string that was too large. After adding the TruncateAllStringsOnAllEntitiesToDbSize line, it works great now! I'm sure there are some optimizations that can go into this, so do please critique/contribute! :-)

    Note: I have only tried this on EF 6.1.3

提交回复
热议问题