Как найти или узнать, где находится тип объекта «не принадлежит» при попытке создать миграцию?

avatar
Mike Lenart
8 августа 2021 в 21:37
46
1
1

У меня есть следующие классы:

  1. Искатель вакансий, владеющий кредитной картой с типом CreditCardType

     public class JobSeeker : Entity
     {
         private readonly List<CreditCard> _creditCards;        
         public IEnumerable<CreditCard> CreditCards => _creditCards.AsReadOnly();
     }
    
     public class CreditCard : Entity
     {
         public CreditCardType CardType { get { return CreditCardType.From(_creditCardTypeID); } private set { } }
         private readonly int _creditCardTypeID;}
    
    
     public class CreditCardType : Enumeration
     {
         public static readonly CreditCardType Amex = new CreditCardType(1, nameof(Amex).ToLowerInvariant());
    
         public static readonly CreditCardType Visa = new CreditCardType(2, nameof(Visa).ToLowerInvariant());
    
         public static readonly CreditCardType MasterCard = new CreditCardType(3, nameof(MasterCard).ToLowerInvariant());
    
         public static IEnumerable<CreditCardType> List() => new[] { Amex, Visa, MasterCard };}
    

Мои конфигурации DBContext:

class JobSeekerEntityTypeConfiguration : IEntityTypeConfiguration<JobSeeker>
{
    public void Configure(EntityTypeBuilder<JobSeeker> jsConfiguration)
    {
        if (jsConfiguration == null)
        {
            throw new ArgumentNullException(nameof(jsConfiguration));
        }

        // Build the model
        jsConfiguration.OwnsOne(s => s.CompleteName);
        jsConfiguration.OwnsOne(s => s.HomeAddress);
        jsConfiguration.OwnsOne(s => s.BillingAddress);
        jsConfiguration.OwnsOne(s => s.EmAddress);
        jsConfiguration.OwnsOne(s => s.PersonalPhoneNumber);

        jsConfiguration.OwnsMany(a => a.CreditCards);

        //jsConfiguration.HasMany<CreditCard>().WithOne(JobSeeker).OnDelete(DeleteBehavior.Restrict);


        jsConfiguration.Property<DateTime>("CreatedDate");
        jsConfiguration.Property<DateTime>("UpdatedDate");
    }
}

class CreditCardTypeEntityTypeConfiguration : IEntityTypeConfiguration<CreditCard>
{
    public void Configure(EntityTypeBuilder<CreditCard> ccConfiguration)
    {
        if (ccConfiguration == null)
        {
            throw new ArgumentNullException(nameof(ccConfiguration));
        }

        // Build the model
        ccConfiguration.HasOne(o => o.CardType).WithMany().HasForeignKey("_creditCardTypeID");

        ccConfiguration.Property<DateTime>("CreatedDate");
        ccConfiguration.Property<DateTime>("UpdatedDate");

    }
}

class CreditCardEntityTypeConfiguration : IEntityTypeConfiguration<CreditCardType>
{
    public void Configure(EntityTypeBuilder<CreditCardType> cctConfiguration)
    {
        if (cctConfiguration == null)
        {
            throw new ArgumentNullException(nameof(cctConfiguration));
        }

        // Build the model
        cctConfiguration.ToTable("CreditCardTypes");

        cctConfiguration.HasKey(o => o.Id);

        cctConfiguration.Property(o => o.Id)
            .HasDefaultValue(1)
            .ValueGeneratedNever()
            .IsRequired();

        cctConfiguration.Property(o => o.Name)
            .HasMaxLength(200)
            .IsRequired();

        cctConfiguration.HasData(
                new { Id = 1, Name = "Amex" },
                new { Id = 2, Name = "Visa" },
                new { Id = 3, Name = "MasterCard" });


    }
}

Контекст моей БД:

public class JobSeekerContext : DbContext, IUnitOfWork
{
    private static readonly Type[] EnumerationTypes = { typeof(CreditCardType) };

    public const string DEFAULT_SCHEMA = "jobseeker";

    private readonly ILoggerFactory MyConsoleLoggerFactory;

    private readonly IMediator Mediator;

    public DbSet<JobSeeker> JobSeekers { get; set; }

    public DbSet<CreditCard> CreditCards { get; set; }
    public DbSet<CreditCardType> CreditCardTypes { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        if (modelBuilder == null)
        {
            throw new ArgumentNullException(nameof(modelBuilder));
        }

        // Build the model
        modelBuilder.ApplyConfiguration(new CreditCardTypeEntityTypeConfiguration());
        modelBuilder.ApplyConfiguration(new CreditCardEntityTypeConfiguration());
        modelBuilder.ApplyConfiguration(new JobSeekerEntityTypeConfiguration());

}

При выполнении переноса я получаю следующую ошибку: "Тип "Кредитная карта" не может быть помечен как принадлежащий, так как не принадлежащий объекту тип с таким именем уже существует."

Где кредитная карта помечена как не принадлежащая?

Источник

Ответы (1)

avatar
Ivan Stoev
9 августа 2021 в 05:34
1

Где CreditCard помечен как не принадлежащий?

В JobSeekerContext здесь

public DbSet<CreditCard> CreditCards { get; set; }

и здесь

modelBuilder.ApplyConfiguration(new CreditCardTypeEntityTypeConfiguration());

и весь (обманчиво названный) класс CreditCardTypeEntityTypeConfiguration, поскольку он IEntityTypeConfiguration<CreditCard>.


Принадлежащие типы объектов — это специальные объекты, которые настраиваются, запрашиваются и обновляются от только до владельца<CreditCard26>.4<

jsConfiguration.OwnsMany(a => a.CreditCards, ccConfiguration =>
{
    // Build the model
    ccConfiguration.HasOne(o => o.CardType).WithMany().HasForeignKey("_creditCardTypeID");
    
    ccConfiguration.Property<DateTime>("CreatedDate");
    ccConfiguration.Property<DateTime>("UpdatedDate");
});

6>.

Вот выдержка из раздела Ограничения по дизайну текущей документации EF Core:

  • Вы не можете создать DbSet<T> для собственного типа.
  • Вы не можете вызывать Entity<T>() с принадлежащим типом на ModelBuilder.

Обратите внимание, что применение класса IEnityTypeConfiguration<T> эквивалентно вызову Entity<T>() на ModelBuilder.

Значит, вы нарушаете оба вышеупомянутых ограничения.

Вам нужно сделать следующее:

  1. Удалить свойство DbSet<CreditCard> из контекста
  2. Удалить класс CreditCardTypeEntityTypeConfiguration и соответствующий вызов ApplyConfiguration
  3. Переместите код конфигурации CreditCard внутрь конфигурации владельца JobSeeker с помощью построителя, предоставленного/возвращенного методом OwnsMany. например
jsConfiguration.OwnsMany(a => a.CreditCards, ccConfiguration =>
{
    // Build the model
    ccConfiguration.HasOne(o => o.CardType).WithMany().HasForeignKey("_creditCardTypeID");
    
    ccConfiguration.Property<DateTime>("CreatedDate");
    ccConfiguration.Property<DateTime>("UpdatedDate");
});