Skip to content

Flexible mapping to CLR types and members (Custom O/C Mapping) #240

Open

Description

This is a grouping of related issues. Feel free to vote (👍) for this issue to indicate that this is an area that you think we should spend time on, but consider also voting for individual issues for things you consider especially important.


This an "epic" issue for the theme of improvements to mapping of different CLR constructs to standard database concepts. Specific pieces of work will be tracked by linked issues.

Done in 7.0

Done in 8.0

Done in 9.0

Backlog


Although we have had support for POCOs through a few major versions, using EF for persistence still places some undesired constraints on the design choices developers can make on their domain objects.

For example, EF Core still requires that mapped CLR types can be instantiated through constructors without parameters (this is only true for navigation properties now), that they contain both property getters and setters for each mapped scalar and reference property, and that all mapped collection navigation properties are exposed as properties that are of a type that implements ICollection<T>.

Note that POCO proxy functionality introduces additional constraints, e.g. lazy loading requires that property getters are virtual and change tracking proxies (not yet supported in EF Core) require that all properties are virtual at the same time that properties mapped to collections are effectively declared as ICollection<T>.

EF Core also requires each entity type in the model to be mapped to a distinct CLR type, which makes some dynamic model scenarios (#2282) harder.

Moreover, scalar properties on objects have to be of a small set of recognized types in order to be mapped (in EF Core the set of types supported nativly by the provider).

Richer constructs such as collections of scalars or collections of complex types, ordered collections, inheritance in complex types, collection manipulation methods, factory methods, and immutable objects are not supported.

This issue tracks the removal of those constrains as a whole and serves as a parent issue for some individual features that we will track independently:

An old hope

One of many interesting design strategies of EF as an O/RMs was that every EF model defined an abstract data model that is separate from the object model. When using EF in regular O/RM scenarios there are in fact three layered models involved: the storage/database model (often referred to as the S-space model), the conceptual/abstract data model (often referred to as the C-space) and the actual object model (also known as the O-space model). EF also makes use of two mapping specifications: the translation of data access operations between the C-space model and the S-space model is the most well-known and where most of the mapping capabilities of EF focus. The mapping between the C-space and the O-space model is less widely known and in fact since only trivial 1:1 mappings are supported.

There are many historical motivations for this underlying design, including the desire to provide a complete “weakly typed“ programming interface (often referred to as a “value layer”) that could be used in scenarios outside the traditional O/RM space, such as runtime metadata driven user interfaces and tools, database reporting, etc. EntityClient was intended to be such weakly typed API, but it had considerable restrictions (e.g. it was read-only) and some usability issues (e.g. it was designed after an ADO.NET provider without a public DbDataAdapter and with a quite complicated connection string format) on the first version of EF. Since its popularity never took off, the investments necessary to unleash the “value layer” were never completed. In the meanwhile, EF role in solving the traditional O/RM scenario of mapping strongly typed objects to database tables and functions became more and more relevant since EF4, so the lion share of the investments have gone into making EF easier to use in those scenarios, which in many cases meant burying the separation between the abstract data model and the object model even deeper under layers of new API.

In practice the object model can be considered for most intents and purposes a straight realization of what is in C-space. The most commonly used APIs on EF take advantage of this similarity and just conflates C-space and O-space seamlessly, abstracting away the fact that there is a layer of indirection. In other words, although this differentiation between C-space and O-space is real and very explicit in the implementation, it is purposely not evident in most of the EF APIs and usage patterns. A clear example of this is Code First. To a great degree, the usability of the Code First API relies on users being able to ignore the existence of an abstract data model.

While sharing the same meta-model for conceptual models has made it easier to expose EF models through things like OData services, the majority of EF users has never needed to know that there is a difference between the conceptual and object models of their applications.

Regardless of the past motivations for creating this extra layer of indirection, there is potential in the decoupling of the conceptual level (at which most of EF’s mapping, query and update pipeline operates) and the objects level. The basic idea is that by breaking the current status quo of 1:1 O-C mapping, it should be possible to extend EF to support much richer object mapping without having to touch at all the guts of the system.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions