简体   繁体   中英

Entity Framework Core - Can't Add Child records

I have a parent child-relationship and I am unable to use the scaffolding command in EF Core because the the child table has no key. I am not allowed to add keys so I am stuck with the architecture.

When I save the changes, I get the following inner exception: Invalid column name 'NewBusinessMasterNbTransactionId'

The code in Startup.cs:

  public void ConfigureServices(IServiceCollection services)
  {
    var connection = Configuration.GetSection("SqlConnection1").Value;
    services.AddScoped<IDharma, DharmaRepo>();
    services.AddDbContext<DharmaContext>(options => options.UseSqlServer(connection));
  }

The code in DharmaContext (I removed most of the data columns to make it shorter):

 public partial class DharmaContext : DbContext
 {
    public DharmaContext()
    {
    }

    public DharmaContext(DbContextOptions<DharmaContext> options)
        : base(options)
    {
    }

    public virtual DbSet<NewBusinessMaster> NewBusinessMaster { get; set; }
    public virtual DbSet<NewBusinessDetail> NewBusinessDetail { get; set; }


    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.HasAnnotation("ProductVersion", "2.2.4-servicing-10062");
        modelBuilder.Entity<NewBusinessMaster>(entity =>
        {
            entity.HasKey(e => e.NbTransactionId);

            entity.ToTable("NewBusiness_Master");

            entity.Property(e => e.NbTransactionId).HasColumnName("NB_TRANSACTION_ID");

            entity.Property(e => e.NbLob)
                .HasColumnName("NB_LOB")
                .HasMaxLength(2)
                .IsUnicode(false);

        });

        modelBuilder.Entity<NewBusinessDetail>(entity =>
        {
            entity.HasKey(e => e.NbTransactionId);

            entity.ToTable("NewBusiness_Detail");

            entity.Property(e => e.NbTransactionId).HasColumnName("NB_TRANSACTION_ID");
        });
            entity.Property(e => e.NbAgentNumber)
                .IsRequired()
                .HasColumnName("NB_AGENT_NUMBER")
                .HasMaxLength(9)
                .IsUnicode(false);
     }
  }

The models (I removed most of the data coumns to make it easier to read):

    public partial class NewBusinessMaster
    {
        public int NbTransactionId { get; set; }
        public string NbLob { get; set; }

        public List<NewBusinessDetail> NewBusinessDetail { get; set; }

        public NewBusinessMaster()
        {
            NewBusinessDetail = new List<NewBusinessDetail>();
        }

    }

    public partial class NewBusinessDetail
    {
        public int NbTransactionId { get; set; }
        public string NbAgentNumber { get; set; }
    }
}

The code to add and save records:

NewBusinessMaster nbMaster = new NewBusinessMaster();
nbMaster.NbLob = "AU";
NewBusinessDetail nbDetailItem = new NewBusinessDetail();
foreach (XElement item in screenH202.Descendants())
{
    nbDetailItem = new NewBusinessDetail();
    if (!string.IsNullOrEmpty(item.Value))
    {
        nbDetailItem.NbAgentNumber = nbMaster.NbAgentNumber;
    }
}
_context.NewBusinessMaster.Add(nbMaster);
 try
 {
    await _context.SaveChangesAsync(); //this line throws the error
 }
 catch (DbUpdateException dbEx)
 {
    throw;
 }

Screenshots of the SQL:

在此处输入图像描述

在此处输入图像描述

By definition, an "entity" is an object with an identifier. It's called Entity Framework for a reason, it's a framework for working with entities, which means they must have primary keys (the identifier).

That said, there might be a couple of options for you here. First, EF Core supports what it calls " owned entities ". These are essentially value objects (an object that acquires its identity from the sum of its values, rather than an explicit identifier, such as an address), and as such, do not have explicit identifier properties. However, they still have a primary key, which is just the foreign key, setting up a one-to-one relationship with the entity that "owns" them. I'm not sure how you would actually scaffold an owned type, though. If you have a table where a foreign key is also a primary key, EF Core may extrapolate that it's an owned type from that, but that may still require adding a primary key to the table, if this is not already the case.

The only other option is what EF Core refers to as query types or keyless entity types (the name has changed in 3.0 to keyless). These are very literally tables or views without a primary key or simply the results from something like a function or stored procedure, matching your scenario here pretty much exactly. However, they can only be read, not inserted or modified, which may not work for your scenario. I'm also not sure how this would be managed with scaffolding. Keyless types are more something you'd manually add to your context, not something EF Core would ever generate for you.

I was finally given permission to add a key to the child table. That made the code simple and I could use the scaffold command.

The classes:

public partial class NewBusinessMaster
{
    public NewBusinessMaster()
    {
        NewBusinessDetail = new HashSet<NewBusinessDetail>();
    }

    public int NbTransactionId { get; set; }
    public string NbLob { get; set; }
    public string NbReferenceNumber { get; set; }
    public string NbAgentNumber { get; set; }
    public string NbEntryOper { get; set; }
    public string NbEffectiveDate { get; set; }
    public string NbInsName { get; set; }
    public string NbInsNameAddr { get; set; }
    public string NbInsAddr { get; set; }
    public string NbInsCity { get; set; }
    public string NbInsState { get; set; }
    public string NbInsZip { get; set; }
    public string NbInsPhone { get; set; }
    public string NbUploadInd { get; set; }
    public DateTime NbCreateDate { get; set; }
    public string NbLockedBy { get; set; }
    public string NbQuoteId { get; set; }

    public virtual ICollection<NewBusinessDetail> NewBusinessDetail { get; set; }
}


public partial class NewBusinessDetail
{
    public int NewBusinessDetailId { get; set; }
    public int NbTransactionId { get; set; }
    public string NbAgentNumber { get; set; }
    public string NbScreenName { get; set; }
    public string NbFieldName { get; set; }
    public string NbFieldValue { get; set; }
    public DateTime? NbLastUpdated { get; set; }

    public virtual NewBusinessMaster NbTransaction { get; set; }
}

//Context
public partial class DharmaContext : DbContext
{
    public DharmaContext()
    {
    }

    public DharmaContext(DbContextOptions<DharmaContext> options)
        : base(options)
    {
    }

    public virtual DbSet<NewBusinessDetail> NewBusinessDetail { get; set; }
    public virtual DbSet<NewBusinessMaster> NewBusinessMaster { get; set; }


    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {

    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.HasAnnotation("ProductVersion", "2.2.4-servicing-10062");

        modelBuilder.Entity<NewBusinessDetail>(entity =>
        {
            entity.Property(e => e.NewBusinessDetailId).HasColumnName("NewBusinessDetail_ID");

            entity.Property(e => e.NbAgentNumber)
                .IsRequired()
                .HasColumnName("NB_AGENT_NUMBER")
                .HasMaxLength(9)
                .IsUnicode(false);

            entity.Property(e => e.NbFieldName)
                .HasColumnName("NB_FIELD_NAME")
                .HasMaxLength(8)
                .IsUnicode(false);

            entity.Property(e => e.NbFieldValue)
                .HasColumnName("NB_FIELD_VALUE")
                .HasMaxLength(1000)
                .IsUnicode(false);

            entity.Property(e => e.NbLastUpdated)
                .HasColumnName("NB_LAST_UPDATED")
                .HasColumnType("datetime")
                .HasDefaultValueSql("(getdate())");

            entity.Property(e => e.NbScreenName)
                .HasColumnName("NB_SCREEN_NAME")
                .HasMaxLength(4)
                .IsUnicode(false);

            entity.Property(e => e.NbTransactionId).HasColumnName("NB_TRANSACTION_ID");

            entity.HasOne(d => d.NbTransaction)
                .WithMany(p => p.NewBusinessDetail)
                .HasForeignKey(d => d.NbTransactionId)
                .OnDelete(DeleteBehavior.ClientSetNull)
                .HasConstraintName("MasterDetail_FK");
        });

        modelBuilder.Entity<NewBusinessMaster>(entity =>
        {
            entity.HasKey(e => e.NbTransactionId);

            entity.Property(e => e.NbTransactionId).HasColumnName("NB_TRANSACTION_ID");

            entity.Property(e => e.NbAgentNumber)
                .IsRequired()
                .HasColumnName("NB_AGENT_NUMBER")
                .HasMaxLength(9)
                .IsUnicode(false);

            entity.Property(e => e.NbCreateDate)
                .HasColumnName("NB_CREATE_DATE")
                .HasColumnType("datetime")
                .HasDefaultValueSql("(getdate())");

            entity.Property(e => e.NbEffectiveDate)
                .HasColumnName("NB_EFFECTIVE_DATE")
                .HasMaxLength(6)
                .IsUnicode(false);

            entity.Property(e => e.NbEntryOper)
                .IsRequired()
                .HasColumnName("NB_ENTRY_OPER")
                .HasMaxLength(3)
                .IsUnicode(false);

            entity.Property(e => e.NbInsAddr)
                .HasColumnName("NB_INS_ADDR")
                .HasMaxLength(30)
                .IsUnicode(false);

            entity.Property(e => e.NbInsCity)
                .HasColumnName("NB_INS_CITY")
                .HasMaxLength(30)
                .IsUnicode(false);

            entity.Property(e => e.NbInsName)
                .HasColumnName("NB_INS_NAME")
                .HasMaxLength(30)
                .IsUnicode(false);

            entity.Property(e => e.NbInsNameAddr)
                .HasColumnName("NB_INS_NAME_ADDR")
                .HasMaxLength(30)
                .IsUnicode(false);

            entity.Property(e => e.NbInsPhone)
                .HasColumnName("NB_INS_PHONE")
                .HasMaxLength(12)
                .IsUnicode(false);

            entity.Property(e => e.NbInsState)
                .HasColumnName("NB_INS_STATE")
                .HasMaxLength(2)
                .IsUnicode(false);

            entity.Property(e => e.NbInsZip)
                .HasColumnName("NB_INS_ZIP")
                .HasMaxLength(11)
                .IsUnicode(false);

            entity.Property(e => e.NbLob)
                .HasColumnName("NB_LOB")
                .HasMaxLength(2)
                .IsUnicode(false);

            entity.Property(e => e.NbLockedBy)
                .HasColumnName("NB_LOCKED_BY")
                .HasMaxLength(3)
                .IsUnicode(false);

            entity.Property(e => e.NbQuoteId)
                .HasColumnName("NB_QUOTE_ID")
                .HasMaxLength(15)
                .IsUnicode(false);

            entity.Property(e => e.NbReferenceNumber)
                .IsRequired()
                .HasColumnName("NB_REFERENCE_NUMBER")
                .HasMaxLength(9)
                .IsUnicode(false);

            entity.Property(e => e.NbUploadInd)
                .HasColumnName("NB_UPLOAD_IND")
                .HasMaxLength(1)
                .IsUnicode(false);
        });
    }


//Code to add parent and child
NewBusinessMaster nbMaster = new NewBusinessMaster();
//set each property of master
//...

nbDetailItem = new NewBusinessDetail();
nbMaster.NewBusinessDetail.Add(nbDetailItem);
_context.NewBusinessMaster.Add(nbMaster);
 try
        {
            await _context.SaveChangesAsync();

        }
        catch (DbUpdateException dbEx)
        {

            throw;
        }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM