[EF Core] ValueConverter를 이용해서 엔터티 속성의 도메인 관리
EF Core를 사용하면서 문자열 길이 등의 특성을 일일이 지정하는 것은 번거롭습니다.
...
[MaxLength(32)]
public string? 제목 { get; set; }
엔터티가 한 개일 때는 상관이 없으나
제목
유형이 여러 엔터티에 사용될 경우 유형을 지정하기 번거롭습니다.
속성 유형을 도메인으로 관리하면 참 편할텐데요, ValueConverter를 이용할 수 있습니다.
그런데 이것을 인터페이스 정적 추상를 사용해서 다음처럼 관리를 하면 편리합니다.
다음 코드 예시는 유형의 길이(MaxLength) 등을 정의해서 활용하는 방법입니다.
public interface IHaveValue<TModel, TProvider>
{
public abstract static TModel Create(TProvider Value);
TProvider Value { get; }
}
public interface IHaveValueWithLength<TModel, TProvider> : IHaveValue<TModel, TProvider>
{
public abstract static int MaxLength { get; }
}
public record Title(string Value) : IHaveValueWithLength<Title, string>
{
public static int MaxLength => 64;
public static Title Create(string Value) => new(Value);
}
| ValueWithLengthConverter.cs
public class ValueWithLengthConverter<TModel, TProvider> : ValueConverter<TModel, TProvider>
where TModel : IHaveValueWithLength<TModel, TProvider>
{
public ValueWithLengthConverter() : base(
v => v.Value,
v => Convert(v),
new ConverterMappingHints(size: TModel.MaxLength)
)
{
}
private static TModel Convert(TProvider value) => TModel.Create(value);
}
다음처럼 적용하고 사용할 수 있습니다.
| DbContext
...
protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
configurationBuilder
.Properties<Title>()
.HaveConversion<ValueWithLengthConverter<Title, string>>();
}
...
| 엔터티
...
public Title? 제목 { get; set; }
...
이제 제목
의 경우 Title
유형을 사용하는 것으로 일관되게 유형 길이가 적용이 됩니다.
uuid를 적용할때도 활용할 수 있습니다. 저는 nanoid-net를 쓸 것인데요, 다음처럼 사용할 수 있습니다.
public record Uid(string Value) : IHaveValueWithLength<Uid, string>
{
public static int MaxLength => 21;
public static Uid Create(string Value) => new(Value);
public static Uid New() => new(Nanoid.Generate(size: MaxLength));
}
public record Suid(string Value) : IHaveValueWithLength<Suid, string>
{
public static int MaxLength => 10;
public static Suid Create(string Value) => new(Value);
public static Uid New() => new(Nanoid.Generate(size: MaxLength));
}
| DbContext
...
protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
configurationBuilder
.Properties<Uid>()
.HaveConversion<ValueWithLengthConverter<Uid, string>>();
configurationBuilder
.Properties<Suid>()
.HaveConversion<ValueWithLengthConverter<Suid, string>>();
}
...
| 엔터티
[Key]
public Uid Id { get; init; } = Uid.New();
잘 적용되네요!