Kros-sk / Kros.KORM

Simple and fast micro-ORM framework for .NET.
MIT License
9 stars 16 forks source link

Use different kind of configuration than attributes #15

Closed Burgyn closed 5 years ago

Burgyn commented 5 years ago

Starting discussion about Use different kind of configuration than attributes from #8.

Current state

Now some configuration is allowed only using attributes (Key, Alias). Something can be changed using custom ModelMapper.

[Alias("Foo")]
public class Foo
{
    [Key("PK_Foo", AutoIncrementMethodType.Identity)]
    public int Id { get; set; }

    [Alias("Name")]
    public string FirstName { get; set; }

    [NoMap]
    public string LastName { get; set; }

    [Converter(typeof(AddressConverter))]
    public IEnumerable<string> Addresses { get; set; }

    [NoMap]
    public IEmailService EmailService { get; set; }
}

Available attributes:

When want use property injection, we must use ModelMapper:

Database.DefaultModelMapper
    .InjectionConfigurator<Foo>()
        .FillProperty(p => p.EmailService, () => new EmailService());

In many scenarios it's OK. However, there are scenarios where we want to have a model definition and mapping it to a database separate. For example, if you want to have entities in domain layer and mapping in infrastructure layer.

Design

The proposal is based on how it is in EF. Have a configuration class where, we are fluent define model mapping to database.

public class DatabaseConfiguration: DatabaseConfigurationBase
{
    public override void OnModelCreating(ModelConfigurationBuilder modelBuilder)
    {
        modelBuilder.Entity<Foo>()
            .HasTableName("Foo")
            .HasPrimaryKey(f => f.Id)
                .HasAutoIncrementMethodType(AutoIncrementMethodType.Identity)
                .HasConstraintName("PK_Foo")
                .Entity
            .Property(f => f.FirstName)
                .HasColumnName("Name")
                .Entity
            .Property(f => f.LastName)
                .NoMap()
                .Entity
            .Property(f => f.Addresses)
                .HasConverter<AddressConverter>()
                .Entity
            .Property(f => f.EmailService)
                .FillProperty(() => new EmailService());
    }
}

Uses in ASP.NET Core applications:

public void ConfigureServices(IServiceCollection services)
{
  services.AddKorm(Configuration)
    .AddKormMigrations(Configuration)
        .UseDatabaseConfiguration<DatabaseCofiguration>()
    .Migrate();
}

Implementation

I tried to explore it. It is possible implemented into KORM.

Burgyn commented 5 years ago

After the discussion with @satano, we propose the following convention:

public class DatabaseConfiguration: DatabaseConfigurationBase
{
    public override void OnModelCreating(ModelConfigurationBuilder modelBuilder)
    {
        modelBuilder.Entity<Foo>()
            .HasTableName("Foo")
            .HasPrimaryKey(f => f.Id)
                .WithName("PK_Foo")
                .AutoIncrement(AutoIncrementMethodType.Custom)
            .Property(f => f.FirstName).HasColumnName("Name")
            .Property(f => f.LastName).NoMap()
            .Property(f => f.Addresses).UseConverter<AddressConverter>()
            .Property(f => f.EmailService).InjectValue(() => new EmailService());
    }
}
Burgyn commented 5 years ago

I'm starting to work on it. You're OK with that.