首页 > 解决方案 > Entity Framework 6.自动截断超过DB Field Length的字符串字段

问题描述

首先,为什么要这样做?在生产系统中,如果传入的数据对于数据库来说太大了,如果字段不重要,您可能希望继续运行并接受数据丢失,如果不插入记录,则会出现更大的问题。

我使用以下代码进行了此操作,但是必须反映私有 .net 框架属性,这很丑陋。

当然有更好的方法来做到这一点?我在另一个帖子上看到了以下代码来加载元数据,但它不起作用。以这种方式加载的类型没有填充数据库字段长度。我们从数据库生成模型。这样我们就不必自己手动调整实体模型(数据库优先方法)。

var metaDataWorkspace = ((IObjectContextAdapter)db).ObjectContext.MetadataWorkspace;
var edmTypes = metaDataWorkspace.GetItems<EdmType>(DataSpace.OSpace);

具有逻辑的方法在下面的 AutoTruncateStringToMaxLength() 中。

有以下用途:

using System.Data.Entity;
using System.Data.Entity.Validation;
using System.Data.Entity.Core.EntityClient;
using System.Data.Entity.Core.Metadata.Edm;

位于部分实体类(例如公共部分类 MyEntities)中的代码:

public override int SaveChanges()
    {
        try
        {
            this.AutoTruncateStringToMaxLength();
            return base.SaveChanges();
        }
        catch (DbEntityValidationException ex)
        {
            List<string> errorMessages = new List<string>();
            foreach (DbEntityValidationResult validationResult in ex.EntityValidationErrors)
            {
                string entityName = validationResult.Entry.Entity.GetType().Name;
                foreach (DbValidationError error in validationResult.ValidationErrors)
                {
                    errorMessages.Add(entityName + "." + error.PropertyName + ": " + error.ErrorMessage);
                }
            }

            // Join the list to a single string.
            var fullErrorMessage = string.Join("; ", errorMessages);

            // Combine the original exception message with the new one.
            var exceptionMessage = string.Concat(ex.Message, " The validation errors are: ", fullErrorMessage);

            // Throw a new DbEntityValidationException with the improved exception message.
            throw new DbEntityValidationException(exceptionMessage, ex.EntityValidationErrors);
        }
    }

    private void AutoTruncateStringToMaxLength()
    {
        var entries = this?.ChangeTracker?.Entries();
        if (entries == null)
        {
            return;
        }

        //********** EDM type from here does not work. MaxLength properties are not set ***************** //
        //var metaDataWorkspace = ((IObjectContextAdapter)db).ObjectContext.MetadataWorkspace;
        //var edmTypes = metaDataWorkspace.GetItems<EdmType>(DataSpace.OSpace);

        ReadOnlyMetadataCollection<EdmMember> memberMetaDataProperties = null;
        string currentloadedEdmType = null;
        foreach (var entry in entries)
        {
            var internalEntry = entry.GetType().GetProperty("InternalEntry", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).GetValue(entry);
            var edmType = (EdmType)internalEntry.GetType().GetProperty("EdmEntityType", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance).GetValue(internalEntry);

            if (edmType != null)
            {
                if (currentloadedEdmType == null || edmType.Name != currentloadedEdmType)
                {
                    currentloadedEdmType = edmType.Name;
                    //seems slow to load (in debug) so cache just in case there is performance issue
                    memberMetaDataProperties = (ReadOnlyMetadataCollection<EdmMember>)edmType.MetadataProperties.FirstOrDefault(x => x.Name == "Members").Value;
                }

                entry.Entity.GetType().GetProperties().ToList().ForEach(p =>
                {
                    var matchingMemberMetaData = memberMetaDataProperties.FirstOrDefault(x => x.Name == p.Name);
                    if (matchingMemberMetaData != null && matchingMemberMetaData.BuiltInTypeKind.ToString() == "EdmProperty")
                    {
                        var edmProperty = (EdmProperty)matchingMemberMetaData;
                        if (edmProperty.MaxLength.HasValue && edmProperty.TypeName == "String")
                        {
                            string value = (p.GetValue(entry.Entity) ?? "").ToString();
                            if (value.Length > edmProperty.MaxLength.Value)
                            {
                                // oops. Its too Long, so truncate it.
                                p.SetValue(entry.Entity, value.Substring(value.Length - edmProperty.MaxLength.Value));
                            }
                        }
                    }
                });
            }
        }
    }

    

标签: c#entity-framework

解决方案


EF Core 有更好的元数据 API。例如

var q = from e in this.Model.GetEntityTypes()
        from p in e.GetProperties()
        where p.ClrType == typeof(string)
        select new { EntityName = e.Name, PropertyName = p.Name, MaxLength = p.GetMaxLength() };

推荐阅读