dotnet / efcore

EF Core is a modern object-database mapper for .NET. It supports LINQ queries, change tracking, updates, and schema migrations.
https://docs.microsoft.com/ef/
MIT License
13.77k stars 3.19k forks source link

Map JSON values stored in database to EF properties #4021

Closed JocaPC closed 2 years ago

JocaPC commented 8 years ago

SQL Server, PostgreSQL, MySQL, and Oracle databases enable developers to store JSON in columns and use values from JSON documents in queries. As an example, we can create product table with few fixed columns and variable information stored as JSON:

Product[id,title,decription,datecreated,info]

info column can contain JSON text. Use cases are:

  1. I can put different non-standard information about products in JSON column as a set of key:value pairs in JSON column, e.g. {"color":"red","price":35.99,"status":1}.
  2. I can have new kind of single table inheritance where I can put all properties specific to some leaf classes as a bag of key:values instead of additional columns.

In SQL Server/Oracle we can use JSON_VALUE function to read JSON values from JSN column by keys, e.g.:

SELECT id, title,
       json_value(info,'$.price'),json_value(info,'$.color'),json_value(info,'$.status')
FROM product

PostgreSQL has ->> operator and MySQL has json_extract function that are similar.

Problem

Currently, JSON fields can be mapped to entities in entity framework as string properties and we can parse them using Json.Net library. It would be good if we could map properties in EF model to (JSON text+path).

Proposal

  1. Basic - Could we map property from EF model to string column that contains text and specify path of value in JSON (e.g. price, status) ? EF can extract json value on JSON path and populate property in EF model with proper type casting.
  2. Medium - Enable updates of properties mapped to json value. If some EF property that is mapped to JSON values is updated, EF could format all of them as JSON and save them back in the in JSON column.
  3. Advanced - Enable LINQ support over JSON properties. If we use Select(obj=>obj.price), or Where(obj => obj.price < 100) in LINQ queries, these predicates could be transformed to JSON_VALUE for SQL Server/Oracle, -> for PostgreSQL. This way we will be able to query JSON values directly from EF.

edited by @smitpatel on 16th March 2018

You can use JSON_VALUE function using user defined function feature in EF Core 2.0 https://github.com/aspnet/EntityFrameworkCore/issues/11295#issuecomment-373852015 explains how to do it for SqlServer.

Some open questions/possible subtasks:

Issues

aaronhudon commented 2 years ago

It’s embarrassing how long they’ve taken. It’s been years now. Those who needed have already implemented their own workarounds by using function references.

Could you possibly explain how or know any links about this? I've been looking myself.

I have had both of the following approaches in production for years.

EF v6 ("OG") This article will get you most of the way. https://stackoverflow.com/a/50490674/459102

EF Core v2.2 It's a bit easier.

Add these to your DbContext (assumes the class name of your DbContext is SqlContext):

        public static string JsonValue(string column, [NotParameterized] string path)
        {
            throw new NotSupportedException();
        }

        public static string JsonQuery(string column, [NotParameterized] string path)
        {
            throw new NotSupportedException();
        }

Then in OnModelCreating map the functions

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.HasDbFunction(typeof(SqlContext).GetMethod(nameof(JsonValue)))
                .HasName("JSON_VALUE")
                .HasSchema("");

            modelBuilder.HasDbFunction(typeof(SqlContext).GetMethod(nameof(JsonQuery)))
                .HasName("JSON_QUERY")
                .HasSchema("");
maumar commented 2 years ago

initial support is now checked in: 401848251cd66f06fffe4baf8ad607f79ef60d05 and 0577a3acab690c9d884889d00e56f3743edb52c4, closing this issue

MoazAlkharfan commented 2 years ago

Will there be support for JsonSerializationOptions?

maumar commented 2 years ago

@MoazAlkharfan eventually, we have https://github.com/dotnet/efcore/issues/28815 to track this