将派生类型传递给重构方法
Passing derived type to refactored method
在我的 EF Fluent API 配置中,我有许多 class 派生自抽象基础 class
public abstract class ImageBase
{
public int ImageId { get; set; }
public string ImageTitle { get; set; }
public string ImageFileExtension { get; set; }
public string ImageDescription { get; set; }
[NotMapped]
public string ImageFileName => BuildImageFilename();
public string ImageUrl { get; set; }
//set this property to true when part of a collection
//if it is the main image of the collection
public bool IsMainImage { get; set; }
//for consistency, all image filenames are the image title, with spaces replaced with underscores
//and the image file extension
private string BuildImageFilename()
{
return $"{ImageTitle.Replace(" ", "_")}{ImageFileExtension}";
}
}
我有很多 class 是从这个派生出来的,下面是一个例子
public class ArticleImageUri : ImageBase
{
[Required]
public int ArticleId { get; set; }
}
在我流利的 API 中 class 我最初有以下
public void Configure(EntityTypeBuilder<ArticleImageUri> builder)
{
//configure primary key
builder.HasKey(u => new { u.ImageId, u.ArticleId })
.HasName("PK_ArticleImageUri");
//configure properties
builder.Property(u => u.ArticleId)
.ValueGeneratedNever()
.IsRequired();
builder.Property(u => u.ImageId)
.ValueGeneratedOnAdd()
.IsRequired();
builder.Property(u => u.ImageDescription)
.HasMaxLength(ConfigurationHelpers.MaxStringLengths.Descriptions)
.IsRequired();
builder.Property(u => u.ImageFileExtension)
.HasMaxLength(ConfigurationHelpers.MaxStringLengths.ShortText)
.IsRequired();
builder.Property(u => u.ImageTitle)
.HasMaxLength(ConfigurationHelpers.MaxStringLengths.FileNames)
.IsRequired();
builder.Property(u => u.ImageFileName)
.HasMaxLength(ConfigurationHelpers.MaxStringLengths.FileNames)
.IsRequired();
builder.Property(u => u.ImageUrl)
.HasMaxLength(ConfigurationHelpers.MaxStringLengths.Urls)
.IsRequired();
//ConfigurationHelpers.SetColumnSizesForImageClasses(builder);
}
注意:ConfigurationHelpers.MaxStringLengths 是静态的,class 即 returns 是列大小的 int。
我将 API 代码重构为方法 SetColumnSizesForImageClasses。
public static void SetColumnSizesForImageClasses(EntityTypeBuilder<ArticleImageUri> builder)
{
//configure column sizes
builder.Property(u => u.ImageDescription)
.HasMaxLength(ConfigurationHelpers.MaxStringLengths.Descriptions)
.IsRequired();
builder.Property(u => u.ImageFileExtension)
.HasMaxLength(ConfigurationHelpers.MaxStringLengths.ShortText)
.IsRequired();
builder.Property(u => u.ImageTitle)
.HasMaxLength(ConfigurationHelpers.MaxStringLengths.FileNames)
.IsRequired();
builder.Property(u => u.ImageFileName)
.HasMaxLength(ConfigurationHelpers.MaxStringLengths.FileNames)
.IsRequired();
builder.Property(u => u.ImageUrl)
.HasMaxLength(ConfigurationHelpers.MaxStringLengths.Urls)
.IsRequired();
}
而且效果很好;仅针对此 class。
我认为只要传入构建器就可以工作,因为构建器已经是类型,但这不起作用。
例如,我有一些其他派生图像类型。
public class MachineImageUri : ImageBase
{
[Required]
public int MachineId { get; set; }
public byte[] ImageThumbnail { get; set; }
}
我希望能够使用重构方法为每个派生类型 Fluent API 配置中的重复字段定义列大小,但我不知道如何传递正确的参数。我尝试使用 T,我认为这是可行的方法,但无法使用它的任何变体。
由于 EntityTypeBuilder<T>
是不变的,您将无法重新使用开箱即用的 Configure
方法。换句话说,您仍然需要两个(或更多)不同的 EF 模型配置。
你可以做的是创建 "helper" 方法,它将接受任何具有特定类型约束的 T
。
static void ConfigureBase<T>(EntityTypeBuilder<T> builder) where T : ImageBase
{
builder.Property(u => u.ImageDescription)
.HasMaxLength(ConfigurationHelpers.MaxStringLengths.Descriptions)
.IsRequired();
builder.Property(u => u.ImageFileExtension)
.HasMaxLength(ConfigurationHelpers.MaxStringLengths.ShortText)
.IsRequired();
builder.Property(u => u.ImageTitle)
.HasMaxLength(ConfigurationHelpers.MaxStringLengths.FileNames)
.IsRequired();
builder.Property(u => u.ImageFileName)
.HasMaxLength(ConfigurationHelpers.MaxStringLengths.FileNames)
.IsRequired();
builder.Property(u => u.ImageUrl)
.HasMaxLength(ConfigurationHelpers.MaxStringLengths.Urls)
.IsRequired();
}
然后您就可以通过以下方式重用它:
ArticleImageUri
配置:
public void Configure(EntityTypeBuilder<ArticleImageUri> builder)
{
ConfigureBase<ArticleImageUri>(builder);
//other specific configurations
}
MachineImageUri
配置:
public void Configure(EntityTypeBuilder<MachineImageUri> builder)
{
ConfigureBase<MachineImageUri>(builder);
//other specific configurations
}
在我的 EF Fluent API 配置中,我有许多 class 派生自抽象基础 class
public abstract class ImageBase
{
public int ImageId { get; set; }
public string ImageTitle { get; set; }
public string ImageFileExtension { get; set; }
public string ImageDescription { get; set; }
[NotMapped]
public string ImageFileName => BuildImageFilename();
public string ImageUrl { get; set; }
//set this property to true when part of a collection
//if it is the main image of the collection
public bool IsMainImage { get; set; }
//for consistency, all image filenames are the image title, with spaces replaced with underscores
//and the image file extension
private string BuildImageFilename()
{
return $"{ImageTitle.Replace(" ", "_")}{ImageFileExtension}";
}
}
我有很多 class 是从这个派生出来的,下面是一个例子
public class ArticleImageUri : ImageBase
{
[Required]
public int ArticleId { get; set; }
}
在我流利的 API 中 class 我最初有以下
public void Configure(EntityTypeBuilder<ArticleImageUri> builder)
{
//configure primary key
builder.HasKey(u => new { u.ImageId, u.ArticleId })
.HasName("PK_ArticleImageUri");
//configure properties
builder.Property(u => u.ArticleId)
.ValueGeneratedNever()
.IsRequired();
builder.Property(u => u.ImageId)
.ValueGeneratedOnAdd()
.IsRequired();
builder.Property(u => u.ImageDescription)
.HasMaxLength(ConfigurationHelpers.MaxStringLengths.Descriptions)
.IsRequired();
builder.Property(u => u.ImageFileExtension)
.HasMaxLength(ConfigurationHelpers.MaxStringLengths.ShortText)
.IsRequired();
builder.Property(u => u.ImageTitle)
.HasMaxLength(ConfigurationHelpers.MaxStringLengths.FileNames)
.IsRequired();
builder.Property(u => u.ImageFileName)
.HasMaxLength(ConfigurationHelpers.MaxStringLengths.FileNames)
.IsRequired();
builder.Property(u => u.ImageUrl)
.HasMaxLength(ConfigurationHelpers.MaxStringLengths.Urls)
.IsRequired();
//ConfigurationHelpers.SetColumnSizesForImageClasses(builder);
}
注意:ConfigurationHelpers.MaxStringLengths 是静态的,class 即 returns 是列大小的 int。 我将 API 代码重构为方法 SetColumnSizesForImageClasses。
public static void SetColumnSizesForImageClasses(EntityTypeBuilder<ArticleImageUri> builder)
{
//configure column sizes
builder.Property(u => u.ImageDescription)
.HasMaxLength(ConfigurationHelpers.MaxStringLengths.Descriptions)
.IsRequired();
builder.Property(u => u.ImageFileExtension)
.HasMaxLength(ConfigurationHelpers.MaxStringLengths.ShortText)
.IsRequired();
builder.Property(u => u.ImageTitle)
.HasMaxLength(ConfigurationHelpers.MaxStringLengths.FileNames)
.IsRequired();
builder.Property(u => u.ImageFileName)
.HasMaxLength(ConfigurationHelpers.MaxStringLengths.FileNames)
.IsRequired();
builder.Property(u => u.ImageUrl)
.HasMaxLength(ConfigurationHelpers.MaxStringLengths.Urls)
.IsRequired();
}
而且效果很好;仅针对此 class。
我认为只要传入构建器就可以工作,因为构建器已经是类型,但这不起作用。 例如,我有一些其他派生图像类型。
public class MachineImageUri : ImageBase
{
[Required]
public int MachineId { get; set; }
public byte[] ImageThumbnail { get; set; }
}
我希望能够使用重构方法为每个派生类型 Fluent API 配置中的重复字段定义列大小,但我不知道如何传递正确的参数。我尝试使用 T,我认为这是可行的方法,但无法使用它的任何变体。
由于 EntityTypeBuilder<T>
是不变的,您将无法重新使用开箱即用的 Configure
方法。换句话说,您仍然需要两个(或更多)不同的 EF 模型配置。
你可以做的是创建 "helper" 方法,它将接受任何具有特定类型约束的 T
。
static void ConfigureBase<T>(EntityTypeBuilder<T> builder) where T : ImageBase
{
builder.Property(u => u.ImageDescription)
.HasMaxLength(ConfigurationHelpers.MaxStringLengths.Descriptions)
.IsRequired();
builder.Property(u => u.ImageFileExtension)
.HasMaxLength(ConfigurationHelpers.MaxStringLengths.ShortText)
.IsRequired();
builder.Property(u => u.ImageTitle)
.HasMaxLength(ConfigurationHelpers.MaxStringLengths.FileNames)
.IsRequired();
builder.Property(u => u.ImageFileName)
.HasMaxLength(ConfigurationHelpers.MaxStringLengths.FileNames)
.IsRequired();
builder.Property(u => u.ImageUrl)
.HasMaxLength(ConfigurationHelpers.MaxStringLengths.Urls)
.IsRequired();
}
然后您就可以通过以下方式重用它:
ArticleImageUri
配置:
public void Configure(EntityTypeBuilder<ArticleImageUri> builder)
{
ConfigureBase<ArticleImageUri>(builder);
//other specific configurations
}
MachineImageUri
配置:
public void Configure(EntityTypeBuilder<MachineImageUri> builder)
{
ConfigureBase<MachineImageUri>(builder);
//other specific configurations
}