Передача производного типа в рефакторированный метод - PullRequest
0 голосов
/ 10 января 2019

В моих конфигурациях EF Fluent API у меня есть ряд классов, производных от абстрактного базового класса

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}";
    }
}

У меня есть несколько классов, которые вытекают из этого, один пример ниже

 public class ArticleImageUri : ImageBase
{
    [Required]
    public int ArticleId { get; set; }
}

В моем свободном API для этого класса у меня изначально было следующее

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 - это статический класс, который возвращает 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();
    }

и это прекрасно работает; только для этого класса.

Я думал, что это сработает, просто передавая компоновщик, поскольку компоновщик уже имеет тип, но это не работает. У меня есть несколько других производных типов изображений, например.

 public class MachineImageUri : ImageBase
{
    [Required]

    public int MachineId { get; set; }

    public byte[] ImageThumbnail { get; set; }
}

Я хочу иметь возможность использовать рефакторированный метод для определения размеров столбцов для дубликатов полей в каждой конфигурации производных типов Fluent API, но я не могу понять, как передать правильные параметры. Я пытался использовать T, что, по-моему, и есть путь, но я не смог заставить его работать.

1 Ответ

0 голосов
/ 10 января 2019

Поскольку EntityTypeBuilder<T> является инвариантом, вы не сможете повторно использовать метод Configure из коробки. Другими словами, вам все равно понадобятся две (или более) разные конфигурации модели EF.

Что вы можете сделать, это создать «вспомогательный» метод, который будет принимать любой 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
}
...