Skip to content

Latest commit

 

History

History
108 lines (88 loc) · 4.43 KB

mapping.md

File metadata and controls

108 lines (88 loc) · 4.43 KB

Mapping entities to database tables

There are two ways how entities could be mapped to database tables:

Fluent API

All mapping tunes in the constructor of EntityProfile class.

Following code provides an example of mapping Book class to the table "books" in schema "sales". HasProperty method has overloads that

  • allows generating a column name automatically, by converting property name to snake-case. In the following example properties: Id, DateOfCreate will have a column name "id", "date_of_create" correspondingly.
  • allows set a custom column name. In the following example property AuthorId is mapped to a "author" column.

So, here we have

  • an Id property that
    • is mapped to an "id" column and
    • is also marked as a private key of this entity
    • is also marked that value of this property is auto generated by the database and it will be updated after insert automatically without executing any additional queries.
  • an AuthorId property that is mapped to an "author" column
  • a DateOfCreate property that
    • is mapped to a "date_of_create" column
    • is also marked that this property will take a value, after insert operation, from database, for instance, the value could be generated by a trigger
  • a DateOfChange property that
    • is mapped to a "last_update" column
    • is also marked that this property will take a value, after update operation, from database, for instance, the value could be generated by a trigger
  • an ISBN property that is mapped to an "isbn" column

If Book class has more properties, they will not be mapped and they will not be passed to a database table. Bulk operations will not change values of these not mapped properties.

public class BookEntityProfile: EntityProfile
{
    public BookEntityProfile():base(typeof(Book))
    {    
        this.ToTable("books", "sales");

        this.HasProperty<Book, int>(entity => entity.Id)
            .ThatIsAutoGenerated()
            .ThatIsPrivateKey();
        this.HasProperty<Book, int>("author", entity => entity.AuthorId);
        this.HasProperty<Book, DateTime>(entity => entity.DateOfCreate)
            .MustBeUpdatedAfterInsert(); 
        this.HasProperty<Book, DateTimeOffset>("last_update", entity => entity.DateOfChange)
            .MustBeUpdatedAfterUpdate();
        this.HasProperty<Book, string>(entity => entity.Isbn);            
    }
}

Decorating properties with attributes

In case you want to map entities with attributes, for example you have legacy entities that are already decorated with DataAnnotation attributes from "System.ComponentModel.Annotations", these entities could be used without any changes.

First of all, your entity profile class should be derived, not from EntityProfile, but from DataAnnotationEntityProfile

For example, we have an entity

[Table("books", Schema = "sales")]
public class Book {
  // Key is an attribute from DataAnnotation library
  // AutoGenerated is an attribute from this, Postgresql Bulk Service library, and indicates that property value is Auto generated
  [Key, AutoGenerated]
  public int Id { get; set; }
  
  [Column("author")]
  public int AuthorId { get; set; }
  
  [UpdateAfterInsert]
  public DateTime DateOfCreate { get; set; }
  
  [UpdateAfterUpdate, Column("last_update")]
  public DateTimeOffset DateOfChange { get; set; }
  
  // Even without any attributes this property will be mapped automatically
  public string Isbn { get; set; }
  
  // In order to exclude property from mapping use NotMappedAttribute from DataAnnotation library
  [NotMapped]
  public string Identity => $"{AuthorId}-{Id}-{Isbn}";
}

For this entity a profile could look like

    public class BookEntityProfile: DataAnnotationEntityProfile<Book>
    {
    }

This would be enough all the mapping happens in the constructor of DataAnnotationEntityProfile.

Mapping with both attributes and fluent api

It is possible to customize mapping in the BookEntityProfile constructor and overide or add some mapping actions.

For example,

    public class BookEntityProfile: DataAnnotationEntityProfile<Book>
    {
        public BookEntityProfile()
        {
            var isbnPropertyProfile = this.Properties[nameof(Book.Isbn)];
            isbnPropertyProfile.MustBeUpdatedAfterInsert();
        }
    }