如何在运行时检查EF模型元数据?

时间:2012-03-05 15:02:09

标签: entity-framework-4 ef-code-first

我需要在保存数据库中的各个字段之前进行一些修剪。我们将xml从另一个应用程序反序列化为EF实体,然后插入它们。 xml中的字段很少超过4000个字符,而不是使用TEXT数据类型,我们想要修剪它们。

我的想法是检查MetadataWorkspace内的DbChangeTrackerMyDbContext.SaveChanges()以查找任何nvarchar(4000)实体属性并修剪任何超过4000的字符串值。但我没有想法如何处理这个问题。我找不到任何相关文件。我看到了一个few related questions,但没有任何细节或提供任何代码示例。

这是我到目前为止所得到的:

public override int SaveChanges()
{
    //TODO: trim strings longer than 4000 where type is nvarchar(max)
    MetadataWorkspace metadataWorkspace = 
        ((IObjectContextAdapter) this).ObjectContext.MetadataWorkspace;
    ReadOnlyCollection<EdmType> edmTypes = 
        metadataWorkspace.GetItems<EdmType>(DataSpace.OSpace);

    return base.SaveChanges();
}

解决方案

这是基于@ GertArnold答案的解决方案。

// get varchar(max) properties
var entityTypes = metadataWorkspace.GetItems<EntityType>(DataSpace.CSpace);
var properties = entityTypes.SelectMany(type => type.Properties)
    .Where(property => property.TypeUsage.EdmType.Name == "String"
           && property.TypeUsage.Facets["MaxLength"].Value.ToString() == "Max"
           // special case for XML columns
           && property.Name != "Xml")
    .Select(
        property =>
            Type.GetType(property.DeclaringType.FullName)
            .GetProperty(property.Name));

// trim varchar(max) properties > 4000
foreach (var entry in ChangeTracker.Entries())
{
    var entity = entry.Entity;
    var entryProperties = 
            properties.Where(prop => prop.DeclaringType == entity.GetType());
    foreach (var entryProperty in entryProperties)
    {
        var value = 
            ((string) entryProperty.GetValue(entity, null) ?? String.Empty);
        if (value.Length > 4000)
        {
            entryProperty.SetValue(entity, value.Substring(0, 4000), null);
        }
    }
}

1 个答案:

答案 0 :(得分:5)

您可以通过以下代码找到属性:

var varchars = context.MetadataWorkspace.GetItemCollection(DataSpace.CSpace)
    .Where(gi => gi.BuiltInTypeKind == BuiltInTypeKind.EntityType)
    .Cast<EntityType>()
    .SelectMany(entityType => entityType.Properties
        .Where(edmProperty => edmProperty.TypeUsage.EdmType.Name == "String")
        .Where(edmProperty => (int)(edmProperty.TypeUsage.Facets["MaxLength"]
            .Value) >= 4000))
    .ToList();

诀窍是通过BuiltInTypeKind.EntityType从模型中提取实体类型,并将其转换为EntityType以访问Properties。 EdmProperty具有属性DeclaringType,用于显示它们属于哪个实体。