2012-03-05 9 views
3

私たちのデータベースにさまざまなフィールドを保存する前にトリミングする必要があります。別のアプリケーションからxmlをEFエンティティに非直列化してから挿入します。 xmlに4000文字を超えるフィールドはほとんどなく、TEXTデータ型を使用するのではなく、代わりにトリムする必要があります。実行時にEFモデルメタデータを検査する方法は?

私の考えはどのnvarchar(4000)エンティティプロパティを見つけて、4000よりも長く、しかし、私はこれにアプローチする方法が分からない任意の文字列値をトリムするMyDbContext.SaveChanges()MetadataWorkspaceDbChangeTrackerを検査することでした。私は関連文書を見つけることができませんでした。私はfew related questionsを見ましたが、細かいことはありませんでした。

は、ここで私はこれまで持っているものです。ここに私のソリューションは、@ GertArnoldの回答に基づいています

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

ソリューション

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

答えて

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によってモデルからエンティティタイプを抽出し、Propertiesへのアクセスを得るためにEntityTypeにこれらをキャストすることです。 EdmPropertyには、どのエンティティが属するかを示すプロパティ​​があります。

+0

これは醜いですが、動作します。ありがとう! – jrummell

+0

同意すると、メタデータモデルの変更に非常に敏感です。 –

関連する問題