在尝试创建迁移时,您如何找到或知道“非拥有”实体类型在哪里?

Posted

技术标签:

【中文标题】在尝试创建迁移时,您如何找到或知道“非拥有”实体类型在哪里?【英文标题】:How do you find or know where the "non-owned" entity type when trying to create a migration? 【发布时间】:2021-10-12 17:27:33 【问题描述】:

我有以下课程:

    拥有具有 CreditCardType 的 CreditCard 的求职者

     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());

当我运行迁移时,我收到以下错误:“无法将类型 'CreditCard' 标记为拥有,因为已经存在同名的非拥有实体类型。”

信用卡在哪里被标记为非所有?

【问题讨论】:

【参考方案1】:

CreditCard 在哪里被标记为非所有?

JobSeekerContext这里

public DbSet<CreditCard> CreditCards  get; set; 

这里

modelBuilder.ApplyConfiguration(new CreditCardTypeEntityTypeConfiguration());

以及整个(误导性命名的)CreditCardTypeEntityTypeConfiguration 类,因为它是 IEntityTypeConfiguration&lt;CreditCard&gt;


Owned entity types 是特殊实体,通过所有者进行配置、查询和更新。

这是当前 EF Core 文档的By-design restrictions 部分的摘录:

您不能为自有类型创建 DbSet&lt;T&gt;。 您不能使用 ModelBuilder 上的自有类型调用 Entity&lt;T&gt;()

请注意,应用IEnityTypeConfiguration&lt;T&gt; 类相当于在ModelBuilder 上调用Entity&lt;T&gt;()

所以你打破了上述两个限制。

你需要做的是

    从上下文中删除 DbSet&lt;CreditCard&gt; 属性 删除CreditCardTypeEntityTypeConfiguration类和对应的ApplyConfiguration调用 使用OwnsMany 方法提供/返回的构建器将CreditCard 配置代码移动到所有者JobSeeker 配置中。例如
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");
);

【讨论】:

以上是关于在尝试创建迁移时,您如何找到或知道“非拥有”实体类型在哪里?的主要内容,如果未能解决你的问题,请参考以下文章

如何创建一个可以调用所有迁移类的主迁移类?

Xcode 8 beta 6 错误:尝试在非拥有协调器上序列化存储访问

创建索引时,具有 mysql 数据库迁移的实体框架失败

无法在实体框架中生成显式迁移

创建索引时,具有mysql数据库迁移的实体框架失败

在 Symfony 上生成迁移时忽略实体