【问题标题】:How to inspect EF model metadata at runtime?如何在运行时检查 EF 模型元数据?
【发布时间】:2012-03-05 15:02:09
【问题描述】:

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

我的想法是检查 MyDbContext.SaveChanges() 内的 MetadataWorkspaceDbChangeTracker 以查找任何 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);
        }
    }
}

【问题讨论】:

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


    【解决方案1】:

    你可以通过这段代码找到属性:

    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,它显示了它们属于哪个实体。

    【讨论】:

    • 同意,它看起来很容易受到元数据模型变化的影响。
    猜你喜欢
    • 2014-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-20
    • 1970-01-01
    • 2011-12-04
    • 1970-01-01
    相关资源
    最近更新 更多