EntityFramework6 - Обратное поколение Poco - Отображение проблем FK - Наследование классов - PullRequest
0 голосов
/ 17 февраля 2020

У меня следующая проблема с использованием генерации и наследования reversepoco из существующей БД. Я унаследовал базу данных и код, который был создан в рамках подхода Devart Model с использованием EF6. У меня есть задание - сначала сделать его Code, чтобы можно было использовать систему миграции CF. БД должна оставаться обратно совместимой.

Для преобразования в CF я использовал генерацию Reverse POCO от Саймона Хьюза. Саймон сделал несколько обновлений для включаемого файла, чтобы включить абстрактные классы и наследование.

На этом этапе я могу создать контекст и получить большую часть данных.

Проблема заключается в том, что БД не соблюдает правильные правила именования CF для FK. Я мог бы исправить 1 уровень наследования, добавив сопоставление в свободный конфигурационный код Api, но когда у меня есть второй или 3 уровень наследования, я не могу получить правильное сопоставление.

На этом этапе я получаю EF исключения, что имена таблиц не найдены: SqlException: недопустимое имя столбца «ReportData_Id». Неверное имя столбца «CompareDataValue_Id». Неверное имя столбца 'DataValue_Id'. Неверное имя столбца «ReportData_Id». Неверное имя столбца 'TextValue_Id'. Неверное имя столбца «ReportData_Id». ...

В следующей части я покажу модель БД (часть), таблицы, классы POCO и конфигурацию. Это много информации, но я хотел дать много информации по мере необходимости. Путь наследования, к которому я хотел бы обратиться: ReportData (базовый класс с идентификатором) -> ReturnData -> DataValue -> CompareDataValue

DB model

Таблицы :

ReportDataTable ReturnDataTable DataValue enter image description here

Классы POCO`1: ReportData

[GeneratedCode("EF.Reverse.POCO.Generator", "v3.1.3")]
// ReportDatas
public partial class ReportData
{
    public int Id { get; set; } // Id (Primary key)
    public DateTime Timestamp { get; set; } // Timestamp
    public int TestStep_Id { get; set; } // TestStep_Id

    // Reverse navigation

    /// <summary>
    /// Parent (One-to-One) ReportData pointed by [ReportDatas_DataBlob].[Id] (FK_DataBlob_inherits_ReportData)
    /// </summary>
    public virtual DataBlob DataBlob { get; set; } // ReportDatas_DataBlob.FK_DataBlob_inherits_ReportData

    /// <summary>
    /// Parent (One-to-One) ReportData pointed by [ReportDatas_LogData].[Id] (FK_LogData_inherits_ReportData)
    /// </summary>
    public virtual LogData LogData { get; set; } // ReportDatas_LogData.FK_LogData_inherits_ReportData

    /// <summary>
    /// Child Tags (Many-to-Many) mapped by table [ReportDataTag]
    /// </summary>
    public virtual ObservableCollection<Tag> Tags { get; set; } // Many to many mapping

    /// <summary>
    /// Parent (One-to-One) ReportData pointed by [ReportDatas_ReturnData].[Id] (FK_ReturnData_inherits_ReportData)
    /// </summary>
    public virtual ReturnData ReturnData { get; set; } // ReportDatas_ReturnData.FK_ReturnData_inherits_ReportData

    // Foreign keys

    /// <summary>
    /// Parent TestStep pointed by [ReportDatas].([TestStep_Id]) (TestStepReportData)
    /// </summary>
    public virtual TestStep TestStep { get; set; } // TestStepReportData

    public ReportData()
    {
        Tags = new ObservableCollection<Tag>();
        InitializePartial();
    }

    partial void InitializePartial();
}

`2: ReturnData

[GeneratedCode("EF.Reverse.POCO.Generator", "v3.1.3")]
// ReportDatas_ReturnData
public partial class ReturnData : ReportData
{
    public bool Valid { get; set; } // Valid
    public TestStatus Status { get; set; } // Status
    public string Comment { get; set; } // Comment

    // Reverse navigation

    /// <summary>
    /// Parent (One-to-One) ReturnData pointed by [ReportDatas_DataHeader].[Id] (FK_DataHeader_inherits_ReturnData)
    /// </summary>
    public virtual DataHeader DataHeader { get; set; } // ReportDatas_DataHeader.FK_DataHeader_inherits_ReturnData

    /// <summary>
    /// Parent (One-to-One) ReturnData pointed by [ReportDatas_DataValue].[Id] (FK_DataValue_inherits_ReturnData)
    /// </summary>
    public virtual DataValue DataValue { get; set; } // ReportDatas_DataValue.FK_DataValue_inherits_ReturnData

    /// <summary>
    /// Parent (One-to-One) ReturnData pointed by [ReportDatas_NumberValue].[Id] (FK_NumberValue_inherits_ReturnData)
    /// </summary>
    public virtual NumberValue NumberValue { get; set; } // ReportDatas_NumberValue.FK_NumberValue_inherits_ReturnData

    /// <summary>
    /// Parent (One-to-One) ReturnData pointed by [ReportDatas_TextValue].[Id] (FK_TextValue_inherits_ReturnData)
    /// </summary>
    public virtual TextValue TextValue { get; set; } // ReportDatas_TextValue.FK_TextValue_inherits_ReturnData

    // Foreign keys

    /// <summary>
    /// Parent ReportData pointed by [ReportDatas_ReturnData].([Id]) (FK_ReturnData_inherits_ReportData)
    /// </summary>
    public virtual ReportData ReportData { get; set; } // FK_ReturnData_inherits_ReportData

    public ReturnData()
    {
        InitializePartial();
    }

    partial void InitializePartial();
}

3: значение данных.

    [GeneratedCode("EF.Reverse.POCO.Generator", "v3.1.3")]
    // ReportDatas_DataValue
    public partial class DataValue : ReturnData
    {
        public byte[] Data { get; set; } // Data

        // Reverse navigation

        /// <summary>
        /// Parent (One-to-One) DataValue pointed by [ReportDatas_CompareDataValue].[Id] (FK_CompareDataValue_inherits_DataValue)
        /// </summary>
        public virtual CompareDataValue CompareDataValue { get; set; } // ReportDatas_CompareDataValue.FK_CompareDataValue_inherits_DataValue

        // Foreign keys

        /// <summary>
        /// Parent ReturnData pointed by [ReportDatas_DataValue].([Id]) (FK_DataValue_inherits_ReturnData)
        /// </summary>

This line is commented out by me. If I leave this in, it’s hiding the ReturnData which is already present in the base class. This might be part of the issue.

       // public virtual ReturnData ReturnData { get; set; } // FK_DataValue_inherits_ReturnData

        public DataValue()
        {
            InitializePartial();
        }

        partial void InitializePartial();
    }

4: CompareDataValue

    [GeneratedCode("EF.Reverse.POCO.Generator", "v3.1.3")]
    // ReportDatas_CompareDataValue
    public partial class CompareDataValue : DataValue
    {
        public byte[] CompareData { get; set; } // CompareData
        public DataCompareType CompareType { get; set; } // CompareType

        // Foreign keys

        /// <summary>
        /// Parent DataValue pointed by [ReportDatas_CompareDataValue].([Id]) (FK_CompareDataValue_inherits_DataValue)
        /// </summary>

This line is commented out by me. If I leave this in, it’s hiding the ReturnData which is already present in the base class. This might be part of the issue.

        //public virtual DataValue DataValue { get; set; } // FK_CompareDataValue_inherits_DataValue

        public CompareDataValue()
        {
            InitializePartial();
        }

        partial void InitializePartial();
    }

Сгенерированные классы конфигурации.

 1: ReportDataConfiguration:

    [GeneratedCode("EF.Reverse.POCO.Generator", "v3.1.3")]
    // ReportDatas
    public partial class ReportDataConfiguration : EntityTypeConfiguration<ReportData>
    {
        public ReportDataConfiguration()
            : this("dbo")
        {
        }

        public ReportDataConfiguration(string schema)
        {
            ToTable("ReportDatas", schema);
            HasKey(x => x.Id);

            Property(x => x.Id).HasColumnName(@"Id").HasColumnType("int").IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
            Property(x => x.Timestamp).HasColumnName(@"Timestamp").HasColumnType("datetime").IsRequired();
            Property(x => x.TestStep_Id).HasColumnName(@"TestStep_Id").HasColumnType("int").IsRequired();

            // Foreign keys
            HasRequired(a => a.TestStep).WithMany(b => b.ReportDatas).HasForeignKey(c => c.TestStep_Id).WillCascadeOnDelete(false); // TestStepReportData
            HasMany(t => t.Tags).WithMany(t => t.ReportDatas).Map(m =>
            {
                m.ToTable("ReportDataTag", "dbo");
                m.MapLeftKey("ReportDataTag_Tag_Id");
                m.MapRightKey("Tags_Id");
            });

            InitializePartial();
        }

        partial void InitializePartial();
    }

2: ReturnDataConfiguration:

    [GeneratedCode("EF.Reverse.POCO.Generator", "v3.1.3")]
    // ReportDatas_ReturnData
    public partial class ReturnDataConfiguration : EntityTypeConfiguration<ReturnData>
    {
        public ReturnDataConfiguration()
            : this("dbo")
        {
        }

        public ReturnDataConfiguration(string schema)
        {
            ToTable("ReportDatas_ReturnData", schema);

This line is commented out by me as the POCO also does not have this.
            //HasKey(x => x.Id);

            Property(x => x.Valid).HasColumnName(@"Valid").HasColumnType("bit").IsRequired();
            Property(x => x.Status).HasColumnName(@"Status").HasColumnType("tinyint").IsRequired();
            Property(x => x.Comment).HasColumnName(@"Comment").HasColumnType("nvarchar(max)").IsRequired();

This line is commented out by me as the POCO also does not have this.
If I leave these in, I can’t even create a context. 

//Property(x => x.Id).HasColumnName(@"Id").HasColumnType("int").IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);


            // Foreign keys
            HasRequired(a => a.ReportData).WithOptional(b => b.ReturnData); // FK_ReturnData_inherits_ReportData

            InitializePartial();
        }

        partial void InitializePartial();
    }

3: DataValueConfiguration
    [GeneratedCode("EF.Reverse.POCO.Generator", "v3.1.3")]
    // ReportDatas_DataValue
    public partial class DataValueConfiguration : EntityTypeConfiguration<DataValue>
    {
        public DataValueConfiguration()
            : this("dbo")
        {
        }

        public DataValueConfiguration(string schema)
        {
            ToTable("ReportDatas_DataValue", schema);
            //HasKey(x => x.Id);

            Property(x => x.Data).HasColumnName(@"Data").HasColumnType("varbinary(max)").IsRequired();

This line is commented out by me as the POCO also does not have this.
If I leave these in, I can’t even create a context.     
//Property(x => x.Id).HasColumnName(@"Id").HasColumnType("int").IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);

            // Foreign keys
            HasRequired(a => a.ReturnData).WithOptional(b => b.DataValue).Map(k=>k.MapKey("Id")); // FK_DataValue_inherits_ReturnData

            InitializePartial();
        }

        partial void InitializePartial();
    }

4: CompareDataValueConfiguration

    [GeneratedCode("EF.Reverse.POCO.Generator", "v3.1.3")]
    // ReportDatas_CompareDataValue
    public partial class CompareDataValueConfiguration : EntityTypeConfiguration<CompareDataValue>
    {
        public CompareDataValueConfiguration()
            : this("dbo")
        {
        }

        public CompareDataValueConfiguration(string schema)
        {
            ToTable("ReportDatas_CompareDataValue", schema);
            //HasKey(x => x.Id);

            Property(x => x.CompareData).HasColumnName(@"CompareData").HasColumnType("varbinary(max)").IsRequired();
            Property(x => x.CompareType).HasColumnName(@"CompareType").HasColumnType("tinyint").IsRequired();

This line is commented out by me as the POCO also does not have this.
If I leave these in, I can’t even create a context.     
//Property(x => x.Id).HasColumnName(@"Id").HasColumnType("int").IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);

            // Foreign keys
            HasRequired(a => a.DataValue).WithOptional(b => b.CompareDataValue).Map(k => k.MapKey("Id")); // FK_CompareDataValue_inherits_DataValue

            InitializePartial();
        }

        partial void InitializePartial();
    }

Мои вопросы:

Какой лучший способ исправить это?

Я мог бы изменить имена таблиц в соответствии со стандартными соглашениями CF. Как тогда должны быть названы столбцы? Следует избегать обновления классов POCO.

Обновление конфигурации, чтобы FK были найдены? Как это сделать?

Другие варианты / предложения?

Я уже читал и выполнял поиск по стеку и попробовал несколько попыток, но не могу его найти. Также следовал курсам от Jul ie Лермана по Pluralsight.

Мне было странно, что даже генератор ReversePoco от Simon пришлось адаптировать для работы с этим типом наследования классов. У нас с Саймоном было много рассылок, чтобы выяснить проблему. Тот факт, что генератор для такой маленькой базы данных и с простыми отношениями позволяет мне думать, что что-то не так в этой БД и как создаются классы.

Любые комментарии и предложения по этому поводу приветствуются! С уважением, Брэм

...