实体框架4.0在插入之前自动截断/修剪字符串

Mas*_*Mas 15 .net entity-framework-4

假设我有一个包含Description Description,varchar(100)列的表.如果尝试插入超过100个字符的字符串,插入将失败.

在插入列之前,Entity Framework中是否有一种方法可以自动截断或修剪字符串以适应列?在我的场景中,我真的不在乎字符串是否被截断,我只是想要插入而不是仅仅失败并记录rror.

由于该模型已经知道了长度限制,我认为Entity Framework可能有办法为我做这个.

如果不支持,最好的方法是什么?扩展自动生成的部分类并覆盖On*Changed方法?我宁愿不对长度限制进行硬编码,而是使用已在实体模型中定义的长度限制.我怎么能访问这个?

编辑

我的最终解决方案是实现自动生成实体的On*Changed部分方法.

我使用这种从实体实例获取ObjectContext的方法,然后使用下面的方法提取最大长度,并截断字符串.

Ric*_*end 8

这将为您提供列的最大长度..

public int? GetColumnMaxLength(ObjectContext context, string entityTypeName, string columnName)
    {
        int? result = null;

        Type entType = Type.GetType(entityTypeName);
        var q = from meta in context.MetadataWorkspace.GetItems(DataSpace.CSpace)
                          .Where(m => m.BuiltInTypeKind == BuiltInTypeKind.EntityType)
                from p in (meta as EntityType).Properties
                .Where(p => p.Name == columnName
                            && p.TypeUsage.EdmType.Name == "String")
                select p;

        var queryResult = q.Where(p =>
        {
            bool match = p.DeclaringType.Name == entityTypeName;
            if (!match && entType != null)
            {
                //Is a fully qualified name....
                match = entType.Name == p.DeclaringType.Name;
            }

            return match;

        }).Select(sel => sel.TypeUsage.Facets["MaxLength"].Value);
        if (queryResult.Any())
        {
            result = Convert.ToInt32(queryResult.First());
        }

        return result;
    }
Run Code Online (Sandbox Code Playgroud)


Jax*_*ian 7

这是我的单线解决方案

(调用它是一行,实现更多一点)

我从@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));
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

消费

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;
}
Run Code Online (Sandbox Code Playgroud)

在此代码之前SaveChanges,当您尝试插入太大的字符串时,会在上面的示例中触发catch.添加TruncateAllStringsOnAllEntitiesToDbSize线后,现在效果很好!我确信有一些优化可以进入这个,所以请批评/贡献!:-)

注意:我只在EF 6.1.3上试过这个