C ා data operation series - 6 EF Core configuration mapping

0. Preface

In the introduction to C ා data operation series - 5. EF Core, we simply demonstrate the functions of EF addition, deletion, modification and query through two classes. Careful partners may have looked at the generated DDL SQL statements and found some clues in them. Those who don't look are not in a hurry, so post them.

public class ModelA
{
	public int Id { get; set; }
	public string Name { get; set; }
	public List<ModelB> ModelBs { get; } = new List<ModelB>();
}
public class ModelB
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int ModelAId { get; set; }
    public ModelA modelA { get; set; }
}

DDL SQL:

CREATE TABLE "ModelBs" (
    "Id" INTEGER NOT NULL CONSTRAINT "PK_ModelBs" PRIMARY KEY AUTOINCREMENT,
    "Name" TEXT NULL,
    "ModelAId" INTEGER NOT NULL,
    CONSTRAINT "FK_ModelBs_ModelAs_ModelAId" FOREIGN KEY ("ModelAId") REFERENCES "ModelAs" ("Id") ON DELETE CASCADE
);
-- auto-generated definition
create table ModelAs
(
    Id   INTEGER not null
        constraint PK_ModelAs
            primary key autoincrement,
    Name TEXT
);

1. Mapping rules

Through a simple example, we can see what the mapping rules of EF are. Based on the principle of configuration, EF regards entity class as a singular type description and table as a collection of entity classes, so the table name is the plural form of class name.

For the primary key, by default, EF will retrieve whether the entity class has an attribute named Id or class name + Id. if there is an EF, it will be considered as the primary key, otherwise it will be considered that the class has no primary key set. If EF finds that the type of primary key is numeric, it will automatically add a self growing constraint.

For other attributes, EF is automatically mapped to the data table in the form of the same name.

For foreign keys, if a reference type is added to a class, and the reference type is also in the context of EF, EF will call this attribute a navigation attribute. Once EF has retrieved the navigation attribute in the class, it will look for the corresponding foreign key. EF will think that the attribute name + Id or the class name + Id may be a foreign key attribute. If it is found that the name is the same and the type is the same as the primary key type of the navigation attribute target class, it is considered a foreign key. If the types are inconsistent, EF considers that the class is set incorrectly. If the attribute that meets the name requirements is not found, EF will add a foreign key attribute by itself.

For one-to-one, EF requires that both sides of the navigation attribute should have foreign key configuration.

One to many, EF requires the other party to set the foreign key. At the same time, if the set type navigation attribute is set on one side, EF will automatically find the foreign key attribute in the target class.

Having said one to one and one to many, what about many to many?

If not declared, EF generates an intermediate table.

2. Modify the mapping relationship

EF allows developers to specify their own mapping rules or mapping rules for individual classes. EF provides several ways to modify mapping relationships.

2.1 data annotation

EF allows developers to contract mapping relationships by using Attribute tags.

Introduce namespace first:

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

Common notes are as follows:

[Table("ModelA")]

Which table does TableAttribute represent for entity mapping

[Key]

KeyAttribute is used to mark which attribute is the primary key

[DatabaseGenerated(DatabaseGeneratedOption.Identity)]

Used to indicate that when this field is first inserted into the database, the value is provided by the database

[ForeignKey("ModelAId")]

Indicates that the specific value of the navigation attribute is maintained by the attribute named ModelAId. If there is no such attribute, EF records are added but not displayed.

[InverseProperty("Author")]

Used on a collection type attribute to indicate which navigation attribute of the source class the collection attribute is related to.

[Column]

Represents a column, which is used to set basic parameters of some columns, such as type and name

[Required]

Indicates that the column cannot be empty when inserting into the database

Using annotations for configuration is quite simple, but it is inevitable that model classes need to be modified and additional namespaces need to be introduced, which does not meet some strict requirements of the project, so Microsoft provides another writing method.

2.2 Fluent mode

When we use this method, we will face a problem: is it to create a new configuration class, or to unify the configuration in the OnModelCreating method in the EF context?

Let's take a look at the declaration of OnModelCreating in EF context:

protected internal virtual void OnModelCreating(ModelBuilder modelBuilder);

Here is a ModelBuilder type. Look at its API and find two methods:

public virtual Microsoft.EntityFrameworkCore.ModelBuilder ApplyConfiguration<TEntity> (Microsoft.EntityFrameworkCore.IEntityTypeConfiguration<TEntity> configuration) where TEntity : class;

public virtual Microsoft.EntityFrameworkCore.Metadata.Builders.EntityTypeBuilder<TEntity> Entity<TEntity> () where TEntity : class;

Continue to look for the identitytypeconfiguration and see that there is only one method for this interface:

void Configure(EntityTypeBuilder<TEntity> builder);

Both point to entitytypebuilder < content > builder, which is the key of Fluent API configuration class. So by analyzing the API, we can get these two writing methods.

So, what are the two options?

When the project is relatively small and there are few data classes, it can be written directly in OnModelCreating. Otherwise, it is recommended to inherit a Configuration interface.

Then, let's see how to configure the mapping relationship through builder:

public class ModelEntityConfig : IEntityTypeConfiguration<ModelA>// Create a new configuration class based on ModelA
{
    public void Configure(EntityTypeBuilder<ModelA> builder)
    {
    }
}
builder.ToTable("TableName");

set a table name

builder.HasKey(t => t.Id);
//builder.HasKey(t => t.Id).HasName("KeyName");

Set the primary key. If you do not write the following HasName, the primary key name is the property name by default; if you write it, EF will use the declared name as the name of the primary key in the database.

var property = builder.Property(t => t.Name);

Gets a PropertyBuilder instance associated with the property Name, through which you can configure the relationship between the property and the database column.

builder.Ignore(t => t.ModelBs);

Indicates that this property is not maintained by the database.

Looking back, let's look at the methods in PropertyBuilder:

// Set a maximum length
public virtual Microsoft.EntityFrameworkCore.Metadata.Builders.PropertyBuilder HasMaxLength (int maxLength);
// Set a data generation rule
public virtual Microsoft.EntityFrameworkCore.Metadata.Builders.PropertyBuilder HasValueGenerator (Func<Microsoft.EntityFrameworkCore.Metadata.IProperty,Microsoft.EntityFrameworkCore.Metadata.IEntityType,Microsoft.EntityFrameworkCore.ValueGeneration.ValueGenerator> factory);
public virtual Microsoft.EntityFrameworkCore.Metadata.Builders.PropertyBuilder HasValueGenerator (Type valueGeneratorType);
public virtual Microsoft.EntityFrameworkCore.Metadata.Builders.PropertyBuilder HasValueGenerator<TGenerator> () where TGenerator : Microsoft.EntityFrameworkCore.ValueGeneration.ValueGenerator;

// Set to automatically generate a value when adding
public virtual Microsoft.EntityFrameworkCore.Metadata.Builders.PropertyBuilder ValueGeneratedOnAdd ();
//Set column name
public static Microsoft.EntityFrameworkCore.Metadata.Builders.PropertyBuilder HasColumnName (this Microsoft.EntityFrameworkCore.Metadata.Builders.PropertyBuilder propertyBuilder, string name);
// Set database parameter type for column
public static Microsoft.EntityFrameworkCore.Metadata.Builders.PropertyBuilder HasColumnType (this Microsoft.EntityFrameworkCore.Metadata.Builders.PropertyBuilder propertyBuilder, string typeName);

3. Summary

In this article, I've led you to see EF Core's content about mapping relationship. I've left the introduction of fluent API related to foreign keys. I'm going to introduce it in the next article. Because this part of the content is more cumbersome, and the usage rate is also quite high.

Please pay attention to more My blog Mr. Gao's Cabin

Tags: C# Attribute Database SQL

Posted on Fri, 15 May 2020 09:44:19 -0400 by mrvijayakumar