【问题标题】:change all string property max length更改所有字符串属性最大长度
【发布时间】:2017-01-02 12:39:50
【问题描述】:
在 EF 6 中我可以这样做:
modelBuilder
.Properties()
.Where(p => p.PropertyType == typeof(string) &&
p.GetCustomAttributes(typeof(MaxLengthAttribute), false).Length == 0)
.Configure(p => p.HasMaxLength(2000));
由于 EF7 ModelBuilder 没有 Properties() 函数,我该如何在 EF7 中做同样的事情?
【问题讨论】:
标签:
c#
entity-framework
entity-framework-core
【解决方案1】:
我认为这是 EF Core 中“仍然缺乏”的功能之一,并希望在以后的版本中添加它。
在那之前,我能建议的最接近的(对于 v1.1.0)如下:
foreach (var p in modelBuilder.Model
.GetEntityTypes()
.SelectMany(t => t.GetProperties())
.Where(p => p.ClrType == typeof(string) && p.GetMaxLength() == null))
{
p.SetMaxLength(2000);
}
【解决方案2】:
EF Core 6.0
为每个数据类型设置自定义默认值变得非常简单(如string):
public class SomeDbContext : DbContext
{
protected override void ConfigureConventions(
ModelConfigurationBuilder configurationBuilder)
{
configurationBuilder
.Properties<string>()
.HaveMaxLength(2000);
}
}
(您可以通过为各个属性指定其他方式来覆盖此类设置。)
更多信息:pre-convention model configuration
【解决方案3】:
FWIW,我在一家公司工作,该公司在将布尔值作为字符存储在数据库中的方式方面存在一些愚蠢的不一致。我创建了一个自定义注释/属性,并希望为我设置的任何 DbSet 找到它。
然后我创建了一个我的上下文继承自的基础 DbContext。它应该在使用public DbSet<Facility> Foo => Set<FooEntity>(); 成员语法定义的继承类中找到任何 DbSet 或 DbSet 派生属性。它通过反射迭代以查找任何定义了我的属性的实体属性。
以下是我基本上所做的。仅在 EF6 上测试,不知道它是否适用于订单版本(对不起)。
public abstract class BaseDbContext: DbContext
{
protected BaseDbContext(DbContextOptions options): base(options)
{
}
/// <summary>
/// Find any DbSets that have properties that implement the Converter attribute
/// and then assign the converter set up in the attribute
/// </summary>
/// <param name="modelBuilder"></param>
/// <exception cref="Exception"></exception>
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// ReSharper disable once ConvertToLocalFunction
var isDbSet = (Type? t) =>
{
while (t != null)
{
if (!t.IsGenericType) return false;
var d = t.GetGenericTypeDefinition();
if (d == typeof(DbSet<>)) return true;
if (d.IsSubclassOf(typeof(DbSet<>))) return true;
t = d.BaseType;
}
return false;
};
foreach (var dbContextProp in this.GetType().GetProperties())
{
var propType = dbContextProp.PropertyType;
if (!isDbSet(propType)) continue;
foreach (var entityType in propType.GenericTypeArguments)
{
var propsWithConverterAttribute = entityType.GetProperties()
.Select(p => (p, p.GetCustomAttribute<ConverterAttribute>()))
.Where(prop => prop.Item2 != null)
.ToArray();
if (!propsWithConverterAttribute.Any()) continue;
var builder = modelBuilder.Entity(entityType);
if (builder == null)
{
throw new Exception($"Unable to build model builder entity for {entityType.Name}");
}
foreach(var (entityProp, attrConverter) in propsWithConverterAttribute)
{
var builderProp = builder.Property(entityProp.Name);
if (builderProp == null)
{
throw new Exception(
$"Unable to get model builder entity property for {entityType.Name}.{entityProp.Name}");
}
builderProp.HasConversion(attrConverter!.Converter);
}
}
}
}
}
public class MyDbContext: BaseDbContext
{
public DbSet<Foo> Foos => Set<Foo>();
public DbSet<Bar> Bars => Set<Bar>();
public FacilityDbContext(DbContextOptions<MyDbContext> options)
: base(options)
{
}
}
public class Foo
{
[Key] [Column("foo_id")] public int ID { get; set; }
[Column("active_flag")]
[Converter(ConverterType.BoolToChar)]
public bool ActiveFlag { get; set; }
}
public enum ConverterType
{
BoolToChar,
BoolToInt
}
[AttributeUsage(AttributeTargets.Property)]
public class ConverterAttribute : Attribute
{
private readonly ConverterType _type;
public ConverterAttribute(ConverterType conversionType)
{
_type = conversionType;
}
public ValueConverter Converter
{
get
{
return _type switch
{
ConverterType.BoolToChar => BoolToCharConverter,
ConverterType.BoolToInt => BoolToCharConverter,
_ => throw new Exception("Invalid converter type")
};
}
}
/// <summary>
/// Convert MySQL char y/n fields to boolean
/// </summary>
private static readonly ValueConverter<bool, char> BoolToCharConverter = new(
v => v ? 'y' : 'n',
v => v != 'n' && v != 'N'
);
/// <summary>
/// Convert MySQL int fields to boolean
/// </summary>
private static readonly ValueConverter<bool, int> BoolToIntConverter = new(
v => v ? 1 : 0,
v => v != 0
);
}