abpframework / abpframework/abp

Better ExtraProperties mapping for EF Core

Open
#23,546 3 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

abp-framework feature
Dominant language
C#
Stars
14.4k
Forks
3.7k
Avg merge
15h 32m
Merged PRs (30d)
106

Description

We are currently using a custom value converter to map a string db field to ExtraPropertyDictionary object when the entity implements IHasExtraProperties interface.

While this is a good way to extend an entity on runtime, it still has come limitations. One of the important limitation is that we can not sort or filter based on the extra properties using EF Core API.

Beginning from EF Core 8, it supports to map owned properties to JSON columns with automatic Dictionary<string, object?> conversion support.

Example code snippets:

Entity:

public class Book : BasicAggregateRoot<Guid>, IHasExtraProperties
{
    public string Name { get; set; }

    public BookType Type { get; set; }

    public DateTime PublishDate { get; set; }

    public float Price { get; set; }
    
    public ExtraPropertyDictionary ExtraProperties { get; set; }

    public Book()
    {
        ExtraProperties = new ExtraPropertyDictionary();
    }
}

Map ExtraProperties to JSON as owned property (removing the configuration added by ABP framework):

builder.Entity<Book>(b =>
{
    b.ToTable(AbpSlnExtraPropDemoConsts.DbTablePrefix + "Books",
        AbpSlnExtraPropDemoConsts.DbSchema);
    b.ConfigureByConvention(); //auto configure for the base class props
    b.Property(x => x.Name).IsRequired().HasMaxLength(128);

    b.Ignore(x => x.ExtraProperties); // I am removing the configuration added by ABP framework
    b.OwnsOne(x => x.ExtraProperties, navigationBuilder =>
    {
        navigationBuilder.ToJson();
        navigationBuilder.Property<bool>("IsAvailable");
        navigationBuilder.Property<int?>("Stock");
    });
});

Order by stock count:

var queryable = await _repository.GetQueryableAsync();
var query = queryable
    .OrderBy(x => EF.Property<bool>(x.ExtraProperties, "Stock"))
    .Skip(input.SkipCount)
    .Take(input.MaxResultCount);

Create a new entity

public async Task<BookDto> CreateAsync(CreateUpdateBookDto input)
{
    var book = ObjectMapper.Map<CreateUpdateBookDto, Book>(input);
    
    book.SetProperty("Stock", 42);
    book.SetProperty("NonExistingProp", "TEST"); // PROBLEM: CAN NOT SAVE!
    
    await _repository.InsertAsync(book);
    return ObjectMapper.Map<Book, BookDto>(book);
}

The main problem here is we can not get/set arbitrary properties. We should have to define them first in the OwnsOne configuration. Of course ABP will make it automatic when we define extra properties to entities, but if we didn't define it, we can not arbitrary set/get values, which is an important breaking change. If we can somehow solve this problem, this will be a better solution than the current one, since it allows us to filter/sort based on extra properties (and use them in linq statements) with db-level query optimization. If we can intercept the EF Core logic that serializes/deserializes the JSON, we may achieve it.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

The issue names no repository files or tests; begin by locating the EF Core configuration for IHasExtraProperties and the ExtraPropertyDictionary value-converter or owned-property mapping. Compare the EF Core 8 OwnsOne/ToJson example with the existing behavior, and consider the work complete when arbitrary extra properties remain readable and writable while defined properties can be filtered or sorted in database queries.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
backend, databases
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.