简体   繁体   中英

EFCore does not create all the columns in the database

im new to EFCore and i don't understand whether it is necessary to specify all the properties in the OnModelCreating() method, because when i don't it does not automatically add them.

for example do i have to add this line for every property of my class in OnModelCreating() :

builder.Entity<Entity>().Property(p => p.PropertyName); 

it appears that EFcore creates columns in the database only if i include them using the previous method, im sure it does not have to be this as i have followed the Ms Docs tutorial and i didn't have to do it, but this time i could not

here is my Model

    public class Block 
    {
        public int SequenceNumber {get ; private set;}
        public virtual BlockHeader Header {get ; private set;}
        public List<Transaction> Transactions {get ; private set;}

        public Block(List<Transaction> transactions,int sequencenumber, BlockHeader header)
        {
            Transactions= transactions;
            Header=header;        
            Header.SequenceNumber=sequencenumber;
            SequenceNumber=sequencenumber;
        }
        public Block(){
        }
    }


 public class BlockHeader
    {
        [MaxLength(256)]
        public byte[] Hash {get ;} 
        [MaxLength(256)]
        public byte[]  PreviousHash { get;}
        public DateTime timestamp { get; }
        public int version{ get; }
        [MaxLength(256)]
        public byte[] MerkleRoot{ get; }
        public int SequenceNumber {get ; set;}
        //this property is used only to configuire the one to one relationship
        public Block block{get;set;}
        public BlockHeader (byte[] previoushash,int sequencenumber,List<Transaction> transactions)
        {
            timestamp = DateTime.Now;
            PreviousHash =  previoushash;
            version = 1;
            MerkleRoot = ComputeMerkleRoot(transactions);
            Hash = ComputeBlockHash();
        }

        public BlockHeader(){

        }
}

and here is Context class:

  class BlockchainDB : DbContext
        {
            public BlockchainDB()
            {
            }
            protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
            {
                optionsBuilder.UseMySQL("server=localhost;database = Blockchain ;user = root ; password = sdeath");
            }
            protected override void OnModelCreating(ModelBuilder builder){
                
                builder.Entity<Block>().HasKey(block => block.SequenceNumber);
                builder.Entity<Block>().HasOne<BlockHeader>(block => block.Header)
                .WithOne(header => header.block)
                .HasForeignKey<BlockHeader>(header => header.SequenceNumber);
                
                builder.Entity<BlockHeader>().Property(p => p.Hash).HasMaxLength(256);
                builder.Entity<BlockHeader>().HasKey(header => header.Hash);
                builder.Entity<BlockHeader>().Property(p => p.MerkleRoot); 
                builder.Entity<BlockHeader>().Property( p => p.PreviousHash); 
            }
            public DbSet<Block> Block {get; set;}
            public DbSet<BlockHeader> blockheader {get; set;}
        }

Am i missing something?

Here is a fully working example console project, that uses data annotations instead of the Fluent API as much as possible (which seems to be what you are looking for). I took the liberty to make some minor changes to the model:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;

namespace IssueConsoleTemplate
{
    public class Block
    {
        [Key]
        public int SequenceNumber { get; private set; }
        
        public BlockHeader Header { get; private set; }
        public ICollection<Transaction> Transactions { get; private set; } = new HashSet<Transaction>();

        public Block(int sequenceNumber, BlockHeader header, ICollection<Transaction> transactions)
        {
            Transactions = transactions;
            Header = header;
            Header.SequenceNumber = sequenceNumber;
            SequenceNumber = sequenceNumber;
        }

        private Block() // <-- can be made private 
        {
        }
    }

    public class BlockHeader
    {
        [Key]
        public int SequenceNumber { get; internal set; }

        [MaxLength(256)]
        public byte[] Hash { get; private set; }

        [MaxLength(256)]
        public byte[] PreviousHash { get; private set; }

        public DateTime TimeStamp { get; private set; }
        public int Version { get; private set; }

        [MaxLength(256)]
        public byte[] MerkleRoot { get; private set; }

        public Block Block { get; private set; }

        public BlockHeader(byte[] previousHash, ICollection<Transaction> transactions)
        {
            Hash = ComputeBlockHash();
            PreviousHash = previousHash;
            TimeStamp = DateTime.Now;
            Version = 1;
            MerkleRoot = ComputeMerkleRoot(transactions);
        }

        private BlockHeader() // <-- can be made private 
        {
        }

        // Stub:
        private byte[] ComputeMerkleRoot(ICollection<Transaction> transactions)
            => Array.Empty<byte>();

        // Stub:
        private byte[] ComputeBlockHash()
            => Array.Empty<byte>();
    }

    public class Transaction
    {
        [Key]
        public int TransactionNumber { get; set; }
        public int SequenceNumber { get; set; }

        public Block Block { get; set; }
    }

    public class BlockchainDB : DbContext
    {
        public DbSet<Block> Blocks { get; set; }
        public DbSet<BlockHeader> BlockHeaders { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder
                .UseMySql(
                    "server=127.0.0.1;port=3306;user=root;password=;database=So63115500",
                    b => b.ServerVersion("8.0.20-mysql"))
                .UseLoggerFactory(
                    LoggerFactory.Create(
                        b => b
                            .AddConsole()
                            .AddFilter(level => level >= LogLevel.Information)))
                .EnableSensitiveDataLogging()
                .EnableDetailedErrors();
        }

        protected override void OnModelCreating(ModelBuilder builder)
        {
            builder.Entity<Block>(
                entity =>
                {
                    entity.HasOne(e => e.Header)
                        .WithOne(e => e.Block)
                        .HasForeignKey<BlockHeader>(e => e.SequenceNumber);
                });

            builder.Entity<Transaction>(
                entity =>
                {
                    entity.HasOne(e => e.Block)
                        .WithMany(e => e.Transactions)
                        .HasForeignKey(e => e.SequenceNumber);
                });
        }
    }

    internal static class Program
    {
        private static void Main()
        {
            using (var context = new BlockchainDB())
            {
                context.Database.EnsureDeleted();
                context.Database.EnsureCreated();

                //
                // Let's add some sample data:
                //
                
                var transactionsBlock1 = new List<Transaction>
                {
                    new Transaction {TransactionNumber = 1},
                    new Transaction {TransactionNumber = 2},
                };
                
                var transactionsBlock2 = new List<Transaction>
                {
                    new Transaction {TransactionNumber = 3},
                    new Transaction {TransactionNumber = 4},
                };
                
                context.Blocks.AddRange(
                    new Block(1, new BlockHeader(Array.Empty<byte>(), transactionsBlock1), transactionsBlock1),
                    new Block(2, new BlockHeader(Array.Empty<byte>(), transactionsBlock2), transactionsBlock2));

                context.SaveChanges();
            }
            
            using (var context = new BlockchainDB())
            {
                var blocksWithHeaderAndTransactions = context.Blocks
                    .Include(b => b.Header)
                    .Include(b => b.Transactions)
                    .ToList();

                Debug.Assert(blocksWithHeaderAndTransactions.Count == 2);
                Debug.Assert(blocksWithHeaderAndTransactions[0].SequenceNumber == 1);
                Debug.Assert(blocksWithHeaderAndTransactions[0].Header != null);
                Debug.Assert(blocksWithHeaderAndTransactions[0].Header.SequenceNumber == 1);
                Debug.Assert(blocksWithHeaderAndTransactions[0].Transactions.Count == 2);
                Debug.Assert(blocksWithHeaderAndTransactions[0].Transactions.First().SequenceNumber == 1);
                Debug.Assert(blocksWithHeaderAndTransactions[0].Transactions.First().TransactionNumber == 1);
            }
        }
    }
}

I used Pomelo.EntityFrameworkCore.MySql as the EF Core provider (and .UseMySql() instead of .UseMySQL() ), which is faster, has way better support and a richer feature set than Oracle's own provider. (Full disclosure, I am the lead developer of the Pomelo provider.)

it appears that EFcore creates columns in the database only if i include them using the previous method, im sure it does not have to be this as i have followed the Ms Docs tutorial and i didn't have to do it, but this time i could not

Try with { get; set; } on all properties – ErikEJ

@ErikEJ what if i dont want to have a setter?

EF Core will also work with properties that have private setters. You can also useBacking Fields instead.

You seem to care a lot about about the visibility of your properties and methods. You might be interested to know then, that the default constructor of the model classes doesn't need to be public.

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