Mas*_*Mas 15 .net entity-framework-4
假设我有一个包含Description Description,varchar(100)列的表.如果尝试插入超过100个字符的字符串,插入将失败.
在插入列之前,Entity Framework中是否有一种方法可以自动截断或修剪字符串以适应列?在我的场景中,我真的不在乎字符串是否被截断,我只是想要插入而不是仅仅失败并记录rror.
由于该模型已经知道了长度限制,我认为Entity Framework可能有办法为我做这个.
如果不支持,最好的方法是什么?扩展自动生成的部分类并覆盖On*Changed方法?我宁愿不对长度限制进行硬编码,而是使用已在实体模型中定义的长度限制.我怎么能访问这个?
编辑
我的最终解决方案是实现自动生成实体的On*Changed部分方法.
这将为您提供列的最大长度..
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)
(调用它是一行,实现更多一点)
我从@elbweb那里获取了代码并根据我的目的进行了调整.在我的情况下,我正在解析EDI文件,其中一些文件有15个不同级别的层次结构,我不想明确指定所有15种不同的类型 - 我想要一个适用于所有实体类型的单行程序.
这有点不同,但现在打电话很轻松.这肯定会对性能产生影响,但对我来说这是可以接受的.基本上把它放在你的DbContext类中,然后它是一个单行程来手动调用(或者你可以通过重写SaveChanges来调用它来自动调用它).
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上试过这个