Efcore: Shared-type entities (part of property bag entities)

Created on 27 Sep 2017  路  21Comments  路  Source: dotnet/efcore

There are entity types that don't have a natural mapping to a CLR type, either because they aren't part of the domain model (e.g. many-to-many join types) or because the CLR types are inaccessible (e.g. migration snapshot). While these could be mapped to shadow entity types #749 that would make working with them harder as they are tightly coupled to the state manager and would need special case handling throughout the stack, especially in the query pipeline.

Property bag entity types are still fully specified at model building time, dynamic types are tracked by #2282. The basic implementation would add support for entities backed up by a Dictionary<string, object> with a predefined entry that contains the entity type name.

Usage:
```C#
modelBuilder.Entity("Cat", c =>
{
c.Property("Id");
c.Property("Name");
});

```C#
context.Add(new Dictionary<string, object>
{
    { "Entity type name", "Cat" },
    { "Id", 123 },
    { "Name", "Tabby" }
});

Related to #2968

area-model-building closed-fixed punted-for-3.0 type-enhancement

All 21 comments

Putting this on the backlog for now; we may pull it in if it is needed for some other 2.1 feature, such as if we allow seeding using navigations.

This issue seems like slight duplication of #2282. I would like repeat myself saying this feature will be very helpful to implement F# type provider for EF Core. Please, consider bumping up priority. Thanks.

@dmitry-a-morozov #2282 is about property bag properties, but this one is about property bag entities, which might or might not contain property bag properties

@AndriySvyryd Thanks for clarification. I think I'm interested in this one then. I know statement about F# can be confusing. Let me know if you need more information on why it's helpful for F#.

@dmitry-a-morozov I believe this would be useful in combination with F# type providers because when the design-time generated types are erased, property bags could act as the runtime type. Is this what you had in mind?

@AndriySvyryd when I wrote the text about property bags in #2282 I was specifically talking about "property bag entities":

Property bags: Currently the EF Core stack assumes a distinct CLR type is mapped to each distinct entity type (and eventually for complex types) in the entity model and a CLR property for each entity property (minus any shadow property). This could be changed to enable EF to materialize and track simple property bags (e.g. any object that implements IDictionary<string, object> or contains an indexer property or any other mechanism to get and set values based on a property name). Even the name of the entity instance belongs to could become another property in the bag. This feature would make working with entity models that are created programmatically easier because it would remove the need to emit new CLR types for each entity and complex type at runtime.

So I am still wondering what you mean when you say these are about two different things :smile:

Anyway, I think it is fine to track property bag entities separately here because #2282 is a meta-issue.

@divega Great ! I'm glad you're familiar with F# and we're on the same page.
Once it's done F# community can start working on type providers for EF Core.

Also, consider working with IDictionary<string, object> interface as oppose to Dictionary<string, object> class so diff implementation can be supplied for example ExpandoObject.

@divega @dmitry-a-morozov Oops, I was thinking about https://github.com/aspnet/EntityFrameworkCore/issues/2968

@AndriySvyryd makes sense. Yep, #2968 is closely related too.

Also, consider working with IDictionary<string, object> interface as oppose to Dictionary<string, object> class...

FWIW, I think it could be interesting to support arbitrary types that have an indexer of the right shape rather than requiring a specific type, i.e. pattern match the indexer, but not sure how much more complicated this would be.

@divega @AndriySvyryd Any chance you can consider this for 2.1?

@dmitry-a-morozov there is a possibility that we will do it in 2.1 or soon after, driven by other features like many-to-many without a join entity, but I wouldn't build plans around it just yet.

@divega since 2.1 is winding down, is this something we could get on the docket for 2.2?

@cartermp why don't we try to come up together with a plan to have EF Core work better with F#? Then we can use that to decide the priority of individual issues. I get how this one can help, however there is also https://github.com/aspnet/EntityFrameworkCore/issues/10731, which makes me wonder if we are missing the whole point :smile:

https://github.com/aspnet/EntityFrameworkCore/issues/10731 is wishful thinking and has no practical value.
F# scaffolding has to be done via Type Providers and currently type providers cannot generate F# records or any other F# specific types for that matter. Currently supported are only .NET 1.1 compatible types. Even generics are not supported. Also many existing and successful type providers do just fine without any F# specific types.

Plan is simple: being able to create __erasing__ F# type providers. Store specific of course.
Except being recommended way to develop type providers _erased_ type provider will have another hidden benefit for EF Core. A type provider must support ad-hoc queries which is ideally done via statically parametrized TP methods which only supported on erased type providers. Any type provider for EF Core that ships without ad-hoc statically typed queries will be unlikely practical for production code.

@weitzhandler How is this related to JSON support?

Fixed size to our estimate.

@ajcvickers since we renamed the size labels some of those I assigned from the planning meeting now don't match (they are marked twice as many weeks as me estimated). I will be reviewing them.

Additional items to tackle

  • Design meeting over self identifying entity instances (#21293)
  • Improve exception message for APIs which cannot figure out the shared type entity type
  • Query roots need to contain IEntityType (Done in https://github.com/dotnet/efcore/pull/19819 which later got converted to query root expression in #20152)

    • Query Test for shared types (#19979)

    • Explicit compiled query(#19979)

  • Replace shadow entity types with property bag entity types (#21294)

Notes from today's design meeting regarding relationship APIs for shared type entity types.

  • string based APIs should not require any changes. The name of entity type should be unique identifier to get the entity type so shared type entities should work same as how shadow entities would work.
  • Lambda based APIs would take string argument which is name of the entity type.

Marking for re-triage, since we need to pull this into 5.0 and assign as appropriate.

Pending items here

  • [x] Add model building APIs for relationships as per design meeting discussion
  • [x] Throw error message when using shared type entity types on context based APIs

Design meeting decisions:

  • Rename Entity(string, Type) to SharedEntity(string, Type)
  • Add SharedEntity(Type) that just marks the type as shared without creating any entity types. Removes entity types created by convention, throws for entity types configured explicitly
  • Don't add relationship APIs with name and lambda or name and type for now
  • UsingEntity will only create a STET if the CLR type is marked as shared
Was this page helpful?
0 / 5 - 0 ratings