-
Notifications
You must be signed in to change notification settings - Fork 0
Guiding Principles
The purpose of this page is to list out the things that help us make decisions when designing/implementing/reviewing EF Core. This will help us make individual decisions that result in a cohesive stack.
NOTE
These are principles and not hard-and-fast rules. Time constraints, user experience, or other circumstances may mean we violate the principles.
The following principles define what we are trying to achieve with EF Core. They shape how we prioritize and design features.
EF Core is a major evolution of EF. It's about building the right stack for the future. We want to be considerate of our past without being constrained by it.
- EF Core is a breaking change release. When there is a better pattern/API/etc. we take the change (unless the benefit is trivial).
- EF Core will not replace EF6 on the day we RTM 1.0.0.
- EF6 will still be the best choice for many applications for some time.
- We are not going to push folks to upgrade, keeping existing application on EF6 is valid and supported.
- Moving from EF6 to EF Core is not an "upgrade" scenario, it's a "port" scenario.
- EF Core is not a re-implementation of EF6 (EF Core has simpler mapping capabilities, no EDM, etc.).
EF Core prioritizes features based on their individual merit rather than EF6 parity.
- EF Core uses the API names from EF6 unless there is a compelling reason to change them.
- If a method/property/type does pretty much the same thing then it has the same name (unless the old name was really bad)
- Names that app developers don't generally type out (i.e. Fluent API return types, low level building blocks, etc.) do not need to stay the same.
EF Core fits into the vision/messaging around Cross-platform .NET, .NET Core, ASP.NET Core, etc.
- We shouldn't be coming up with messaging around cross-platform/lightweight/modular/re-write at the EF level.
- We're just part of the larger picture of what's happening in .NET at Microsoft.
EF Core runs everywhere that people write .NET code
- The core runs everywhere, but not all providers will run on every platform.
- EF Core supports the default provider(s) for each platform (i.e. SQL Server for Windows, SQLite for devices, Postgres/MySql for Mac/Linux).
EF Core supports new data stores (relational and non-relational)
- EF Core is a great O/RM. We don't want to sacrifice the relational experience in order to light up new data stores.
- EF Core allows O/RM concepts/patterns to be used with non-relational data stores.
- EF Core is not trying to replace SDKs for non-relational stores. It is an option for folks who want the O/RM like patterns.
- EF Core does not hide the type of database you are targeting. We are not building a magical abstraction where the same model can transparently target different types of providers. We provide a common set of building blocks but there are provider specific APIs (e.g. configuring row/partition key on Azure Table Storage, beginning a DbTransaction on a relational database).
EF Core is optimized around being a simple, intuitive O/RM
- EF Core is not a micro-O/RM (it still supports LINQ, change tracking, updates, etc.)
- EF Core favors an opinionated "this is how you do things" approach over "we support any mapping pattern".
- EF Core allows you to map the same database schemas as past releases of EF, but your domain objects may not be able to drift as much from the shape of your schema.
- EF Core allows you to easily circumvent O/RM features when you need to get close to the metal (e.g. drop down to SQL when LINQ doesn't work).
EF Core is lightweight and composable.
- EF Core will be built with memory and CPU usage in mind
- EF Core will be built to avoid unnecessary abstraction/layering between top level APIs and the database (i.e. "closer to the metal" that EF6)
- EF Core is pay-per-play (i.e. if you don't use SQL Server/commands/etc. then you don't download, reference, deploy, or load the binaries)
- EF Core is built over composable building blocks (i.e. you can override/replace individual components, drop down to low level metadata model, etc.)
The following constrains define the scope for where EF Core needs to work well. They allow us to design features that work well within the defined scope and don't have to be complicated or degraded by supporting scenarios outside the scope. They allow us to not invest time fixing bugs that are outside the defined scope.
SQL Server
- EF Core supports SQL Server 2008 onwards. Things need to work well by default with 2012. It's ok to have to change settings etc. to work on 2008.
- EF Core works well by-default on SQL Azure (i.e. without changing settings etc.).
Platforms
- EF Core supports .NET 4.5.1 onwards
- EF Core doesn't have to support older versions of each platform (i.e. Win10 UWP support is more important than Win81, Mono 4 over Mono 3.x, etc.).
The following conventions help us have a consistent API across our product. We also encourage provider writers to follow the same conventions.
Prefixes
- We don't have a global prefix that we use everywhere (in EF6 we think we overdid the "Db" prefixing)
- We use the "Db" prefix where there is a need to qualify something to EF (usually when it is a very general concept such as "Model")
- Types that implement a base type, interface, etc. from Core (i.e. the relational implementation of DataStore) use the same namespace as the type they implement and append a library specific prefix (i.e. RelationalDataStore).
- Example prefixes:
- Relational
- SqlServer
- Sqlite
- InMemory
Postfixes
- When applying the a postfix we do not shorten the name of the component it relates to (i.e. DbModel/DbModelBuilder is correct and DbModel/ModelBuilder would be wrong)
- Common postfixes:
- Factory = a component that creates a new instance of a particular type
- Source = a component that locates the correct instance of a particular type
- Cache = a component that creates or selects a component based on its presence in a cache
- Builder = a component that provides an API for constructing an instance of another type. The type being constructed may or may not be immutable.
Visibility
- By default everything is public (see Namespaces for info on categorizing things that are "Internal")
- If we have helper types that are strictly an implementation detail, have no foreseeable use to external code, and are ugly to have in public API we may choose to make them internal (these should be very limited).
Namespaces
- Our root namespace (
Microsoft.EntityFrameworkCore) is only for types that users directly reference in their code for the majority of applications (i.e.DbContext,DbSet, etc.) - We group related components into a sub-namespace if there are enough types (~5 types) or we think there will be in the future.
- Components that don't have a grouping go into the
Infrastructurenamespace - We use an
Internalsub-namespace to identify components that would historically have been internal types. - We do not guarantee that these APIs will not break/change/etc. between releases (including minor/patch releases)
- We do not document these types
Extension Methods
- Extension methods typically go in the namespace of the type they target so that they are easily discovered without importing namespaces
- Exceptions to this are for very common types where you may have EF referenced but the extension methods don't make sense in all places you use the target type, or the extensions methods have a generic name that may collide with other extension methods (e.g.
IQuerable<T>.ToListAsynclives inMicrosoft.EntityFrameworkCorerather thanSystem.Linq)