简体   繁体   中英

Ways to map database with Entity Framework?

How many ways are there to map a database with Entity Framework in .NET?

I understand there is code-first and database-first (using .EDMX wizard for example).

Within the context of database-first, can I map my tables and relationships manually without using .EDMX ? How many ways exist and which do you recommend?

Are there libraries for manual table mapping, which are the best?

I think there is not a best way, but maybe there is a way that fits best your needs. I'll try to explain the ways you have, than you can choose the best for you.

On high level, there are two options:

  • DB first: you define the database and let a tool to create your model classes
  • Code first: you define your classes and let EF manage the tables for you

Mainly DB first is the best for:

  • Map an already existing database: in this situation your DB is already designed, so you have only to map entities
  • Your focus is the DB structure: in this situation, better if you design your DB as you want, then let a tool to map your entities

Code first is the best when you don't mind about the DB but you want to think about the object model. Of course, you can change how the DB is generated using data annotation or any other way EF gives you, but the focus for you has to be the object model.

Hi yes can can absolutely Map a database from EF. It is called scaffolding . What it does is it creates the database as models and required files for you.

Once you open the package manage or cmd you can type the following one-liner to scafford you database:

CMD:

dotnet ef dbcontext scaffold "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=Chinook" Microsoft.EntityFrameworkCore.SqlServer

Package Manager:

 Scaffold-DbContext "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=Chinook" Microsoft.EntityFrameworkCore.SqlServer 

See the EF Core tutorial on it on the official windows website:

https://docs.microsoft.com/en-us/ef/core/managing-schemas/scaffolding?tabs=dotnet-core-cli

And for EF6 there is a great tutorial right here:

https://www.illucit.com/en/asp-net/entity-framework-7-code-first-migrations/

For full manual control with a Database-First project you can leverage a combination of convention, attributes, and/or entity configurations to configure the entities. Scaffolding I find works 90% of the time, but usually there will be some aspect of a production schema, especially where you don't have the flexibility to change the schema to make it more ORM-friendly, that scaffolding doesn't quite handle.

Also, if you're adopting something like bounded contexts (think DbContexts with fit-for-purpose mappings) and want to customize how tables/views map to entities, then it helps to be more explicit with the mapping. For example, for general entities I will map navigation properties, but in cases where I want raw performance over larger operations I will want to forgo declaring navigation properties and work strictly with FK columns. The less "mapping" a DbContext has to worry about and fewer entities it is tracking, the faster it performs.

Attributes: Here you declare your entity classes and use the appropriate attributes to describe the table, key, and other aspects such as column renames etc.

Ie

[Table("tblOrders", "App")] // tblOrders table in App namespace
public class Order
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int OrderId { get; set; }
    [Column("OrderNum")]
    public string OrderNumber { get; set; }
    public string OrderRef { get; set; }


    [ForeignKey("Customer")]
    public int CustomerId { get; set; }
    public virtual Customer Customer { get; set; }
}

This works for the 90-%ile of cases where you want to set up entities. For simple columns that you don't need to rename etc. you don't need to add attributes and leave it to convention.

Entity Configuration: The commonly referenced means of doing this is to use the DbContext's OnModelCreating override and use modelBuilder to configure the entities. For smaller system with a couple handfuls of entities this can be manageable, but for larger systems this can get rather bloated since everything ends up in one method, or a chain of method calls to break it up.

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);

    modelBuilder.Entity<Order>()
        .ToTable("tblOrders", "App")
        .HasKey(x => x.OrderId)
        .Property(x => x.OrderId)
            .HasDatabaseGenerated(DatabaseGeneratedOption.Identity);

    modelBuilder.Entity<Order>()
        .Property(x => x.OrderNumber)
            .HasColumnName("OrderNum);

    modelBuilder.Entity<Order>()
        .HasRequired(x => x.Customer)
        .WithMany(x => x.Orders)
        .HasForeignKey(x => x.CustomerId);
   
}

The lesser documented option is to leverage EntityTypeConfigration<TEntity> ( IEntityTypeConfiguration<TEntity> in EF Core)

public class OrderConfiguration : EntityTypeConfiguration<Order>
{
    public OrderConfiguration()
    {
        ToTable("tblOrders", "App");
        HasKey(x => x.OrderId)
            .Property(x => x.OrderId)
            .HasDatabaseGenerated(DatabaseGeneratedOption.Identity);

        Property(x => x.OrderNumber)
            .HasColumnName("OrderNum");

        HasRequired(x => x.Customer)
            .WithMany(x => x.Orders)
            .HasForeignKey(x => x.CustomerId);
    }
}
       

From there the DbContext just needs to be initialized to load the entity type configurations. This is done in the OnModelCreating which you can do explicitly, or add all Configurations by assembly.

modelBuilder.Configurations.AddFromAssembly(GetType().Assembly);

Personally, I default to declaring EntityTypeConfigurations for all entities as I prefer to rely on convention as little as possible. Being explicit with the configuration means you have something to investigate and work with where a convention doesn't work the way you expect, and it allows you to declare mappings for things like ForeignKeys without declaring FK properties in the entities. (Highly recommended to avoid two sources of truth about a relationship, being the FK and the navigation property)

My projects will commonly have a.Data project where I will keep the Entities, DbContext, and Repositories for a project. The EntityTypeConfiguration instances I place under /Entities/Configuration. They could just as easily be housed in the entity class files, as internal members of the entity class itself, or nested under the Entity class. (Ie using a plugin like NestIn)

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