Написание специального соглашения «добавить теневой ПК»C#

Место общения программистов C#
Ответить
Anonymous
 Написание специального соглашения «добавить теневой ПК»

Сообщение Anonymous »

Я пытаюсь написать соглашение для массовой настройки модели. Он должен добавить первичный ключ к базовому классу типа сущности вместе с некоторыми другими менее важными вещами. Нам это нужно, поскольку мы обнаружили, что ключи, добавленные EF Core, не используют правильный тип CLR ( вместо uint), а также потому, что у нас есть общие типы сущностей и мы не хотим настраивать каждый конкретный тип как сущность отдельно.
Но мы не получаем далеко. EF Core сообщает нам следующее:

Невозможно создать «DbContext» типа «Контекст». Исключение «Тип объекта «DirectoryReference» требует определения первичного ключа. Если вы намеревались использовать тип объекта без ключа, вызовите HasNoKey в OnModelCreating. Дополнительные сведения о типах объектов без ключа см. на странице https://go.microsoft.com/fwlink/?linkid=2141943.' был выброшен при попытке создать экземпляр. Информацию о различных шаблонах, поддерживаемых во время разработки, см. на странице https://go.microsoft.com/fwlink/?linkid=851728

Но мы их настроили. в соглашении:

Код: Выделить всё

public class IdShadowPropertyConvention: IEntityTypeBaseTypeChangedConvention, IEntityTypeAddedConvention
{
static IdShadowPropertyConvention()
{
File.Delete("efcore.log");
}
public void ProcessEntityTypeAdded(IConventionEntityTypeBuilder builder, IConventionContext context)
{
File.AppendAllText("efcore.log", $"[ProcessEntityTypeAdded] Entity `{builder.Metadata.Name}`, {builder.Metadata.IsInModel}, {builder.Metadata.HasSharedClrType}, `{builder.Metadata.BaseType?.Name}`.\n");
using var t = context.DelayConventions();
if(builder.Metadata is { IsInModel: true, HasSharedClrType: false, BaseType: null } && !builder.Metadata.IsOwned())
{
var type = builder.Metadata.ClrType;
if(type.BaseType != typeof(object))
{
var entity = builder;
do
{
type = type.BaseType!;
var baseEntity = builder.ModelBuilder.Metadata.FindEntityType(type)?.Builder ?? builder.ModelBuilder.Entity(type)!;
if(!entity.Metadata.HasSharedClrType && !entity.Metadata.IsOwned())
{
File.AppendAllText("efcore.log", $"\tSet a new base type (transitive): `{entity.Metadata.Name}` => `{baseEntity.Metadata.Name}`.\n");
_ = entity.HasBaseType(baseEntity.Metadata);
}
entity = baseEntity;
}
while(type.BaseType != typeof(object));
}
IConventionKeyBuilder? pk1 = null;
{
var baseEntity = builder.ModelBuilder.Entity(type);
File.AppendAllText("efcore.log", $"\tBase type: {type.ShortDisplayName()}, `{baseEntity?.Metadata.HasSharedClrType}`, `{baseEntity?.Metadata.IsKeyless}`.\n");
if(baseEntity == builder)
{
if(baseEntity.Metadata is { HasSharedClrType: false } meta)
{
if(!baseEntity.Metadata.IsKeyless)
{
var prop = baseEntity.Property(typeof(uint), "Id");
File.AppendAllText("efcore.log", $"\tAdded an ID property: `{prop}`.\n");
var pk = prop is null ? baseEntity.PrimaryKey(["Id"]) : baseEntity.PrimaryKey([prop.Metadata]);
pk1 = pk;
File.AppendAllText("efcore.log", $"\tAdded a primary key: `{pk?.Metadata.GetName()}`.\n");
}
_ = baseEntity.UseMappingStrategy(RelationalAnnotationNames.TphMappingStrategy)?.HasDiscriminator();
File.AppendAllText("efcore.log", $"\tConfigured as a base type.\n");
}
}
}
_ = builder.Property(typeof(uint), "RowVersion")?.ValueGenerated(ValueGenerated.OnAddOrUpdate)?.IsConcurrencyToken(true);
var pk2 = builder.Metadata.FindDeclaredPrimaryKey();
File.AppendAllText("efcore.log", $"\tPKs: `{pk1?.Metadata.Properties.Select((p) => p.Name).Join(", ")}`, `{pk2?.Properties.Select((p) => p.Name).Join(", ")}`.\n");
}
}

public void ProcessEntityTypeBaseTypeChanged(IConventionEntityTypeBuilder entityTypeBuilder, IConventionEntityType? newBaseType, IConventionEntityType? oldBaseType, IConventionContext  context)
{
File.AppendAllText("efcore.log", $"[ProcessEntityTypeBaseTypeChanged] Entity `{entityTypeBuilder.Metadata.Name}`, {entityTypeBuilder.Metadata.IsInModel}, {entityTypeBuilder.Metadata.HasSharedClrType}, BT: `{entityTypeBuilder.Metadata.BaseType?.Name}`, OT: `{oldBaseType?.Name}`, NT: {newBaseType?.Name}`, OBT: `{oldBaseType?.BaseType?.Name}`, NBT: `{newBaseType?.BaseType?.Name}`.\n");

if(newBaseType?.IsInModel is true)
{
var type = newBaseType;
while(type.BaseType is not null)
{
type = type.BaseType;
}
File.AppendAllText("efcore.log", $"\tBase type: {type.Name}, `{type.HasSharedClrType}`, `{type.IsKeyless}`.\n");
if(type.BaseType is null)
{
if(!type.IsKeyless)
{
var prop = type.Builder.Property(typeof(uint), "Id");
File.AppendAllText("efcore.log", $"\tAdded an ID property: `{prop}`.\n");
var pk = prop is null ? type.Builder.PrimaryKey(["Id"]) : type.Builder.PrimaryKey([prop.Metadata]);
File.AppendAllText("efcore.log", $"\tAdded a primary key: `{pk?.Metadata.GetName()}`.\n");
}
_ = type.Builder.Property(typeof(uint), "RowVersion")?.ValueGenerated(ValueGenerated.OnAddOrUpdate)?.IsConcurrencyToken(true);
_ = type.Builder.UseMappingStrategy(RelationalAnnotationNames.TphMappingStrategy)?.HasDiscriminator();
}
}
}
}
Изучая полученный журнал, мы видим следующие важные части:

Код: Выделить всё

[ProcessEntityTypeAdded] Entity `DirectoryReference`, True, False, ``.
Set a new base type (transitive): `DirectoryReference` => `DirectoryReference`.
Base type: DirectoryReference, `False`, `False`.
PKs: ``, ``.
[ProcessEntityTypeAdded] Entity `DirectoryReference`, True, False, ``.
Base type: DirectoryReference, `False`, `False`.
Added an ID property: `Microsoft.EntityFrameworkCore.Metadata.Internal.InternalPropertyBuilder`.
Added a primary key: `PK_directory_reference_directory_entry_foo`.
Configured as a base type.
PKs: `Id`, `Id`.
[ProcessEntityTypeBaseTypeChanged] Entity `DirectoryReference`, True, False, BT: `DirectoryReference`, OT: ``, NT: `DirectoryReference`, OBT: ``, NBT: ``.
Base type: DirectoryReference, `False`, `False`.
Added an ID property: `Microsoft.EntityFrameworkCore.Metadata.Internal.InternalPropertyBuilder`.
Added a primary key: `PK_directory_reference_directory_entry_foo`.
[ProcessEntityTypeBaseTypeChanged] Entity `DirectoryReference`, True, False, BT: ``, OT: `DirectoryReference`, NT: ``, OBT: ``, NBT: ``.
Очевидно, что-то в EF Core переопределило нашу конфигурацию и сбросило базовый тип объекта на нет. Мы попытались переместить код изменения базового типа в соглашение о завершении модели, но к тому времени FK уже установлены и больше не позволяют изменять базовый тип, и не похоже, что их будет легко перенацелить на базовый тип. .
Как мы можем предотвратить такое переопределение нашего соглашения EF Core?

Подробнее здесь: https://stackoverflow.com/questions/792 ... convention
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»