Code Monkey home page Code Monkey logo

ef6's Introduction

EF6

Bsg.EF6 is a .Net based framework, extending Microsoft's Entity Framework 6 (Code First) with a specific focus on bulk operations. The framework is used internally by the .Net teams at Business Systems Group when working with Entity Framework 6.

What is its purpose?

The aim of the framework is leverage off the DbContext's standard functionality to automatically generate raw sql from strongly-typed IQueryables and then combine these parameterised SELECT SQL statements with custom SQL to perform bulk SQL operations (INSERTS, UPDATES, DELETES etc.) in one command, directly on the SQL server without requiring the DbConext to submit multiple requests from the Application Layer.

What are the advantages to using it?

Using this framework can reduce the work load and memory requirements on the Application Server, reduce the number of (and frequeny of opening and closing) connections required to communicate with the Database Server and significantly reduce the network traffic between the two. Whilst at the same time still leveraging most of the usual benefits of a traditional ORM.

What does this actually mean?

It means you can run bulk update, insert and delete SQL statements directly on the Database server, but still make use of a ORM. I.e. you get the performance of SQL and the usability of the ORM.

How is this different from other Bulk EF frameworks?

For some parts, its very similar especially with regards to the BulkAdd, BulkDelete and BulkUpdate type functionality. Its more unique value proposition comes from the SelectAndAdd and SelectAndUpdate methods, which allow for bulk (many) and unique (per row) updates and inserts without sending any additional data across the network (assuming all the data needed for the update or insert already resides within the Database)

BulkDelete & BulkUpdate

BulkAdd

Overview

Delete or update multiple entities in a single call based on a Predicate Expression (lamda) or IQueryable of that type.

When To Use

For BulkDelete, when you need to delete many (but not necessarily all) records without reseeding the primary keys back to 0 and are able to define a predicate type expression or provide a IQueryable collection of that type.

If only 1 record is required to be deleted consider using the non bulk methods.

If all records are to be deleted consider using the Truncate methods.

For BulkUpdate, when you need to update a selection (via a predicate expression or an IQueryable) of records with a constant update (i.e. same values for everyrow to be updated).

If only 1 record is required to be updated consider using the standard EF change tracking functionality.

If many records are to be updated uniquely (same properties but different values depending on the record to be updated) and these new values can be found from data already residing within the database, then consider using the SelectAndUpdate methods.

Examples

Delete with IQueryable

var recordsToDelete = someRepo.FindAll(e => !e.IsActive);
someRepo.BulkDelete(recordsToDelete);

Delete with Predicate Expression

someRepo.BulkDelete(e => !e.IsActive);

Update with IQueryable

var recordsToDelete = someRepo.FindAll(e => !e.IsActive);
someRepo.BulkDelete(recordsToDelete);

Update with Predicate Expression

var recordsToUpdate = someRepo.FindAll(e => !e.IsActive);
someRepo.BulkUpdate(recordsToUpdate, e => new SomeEntity { IsActive = true, Comment = "Reactivated" });

BulkAdd

BulkAdd

Overview

Insert multiple entities in large batches rather than on a row by row basis. Behind the scenes these methods make use of DataTables and SQL Bulk Copy and related .Net libraries.

When To Use

When multiple records are required to be inserted and the data currently resides only on the application server side (i.e. not within the database).

If only 1 record is required to be inserted and / or the autogenerated Id is required immediately from this inserted entity, then use the standard EF change tracking functionality.

If many records are required to be created, but the data to create, compose and/ or aggregate these new records is all available within the database, then consider using the SelectAndAdd methods.

Examples

var newEntities = new List<SomeEntity>();

...code to create entities...

someRepo.BulkAdd(newEntities);

Truncate

BulkAdd

Overview

Remove all entities from a table and reset the autogenerated Id back to 0.

When To Use

Because the SQL Trunacte command won't work on tables with foreign key references, 2 truncate methods are provided.

If only some records are required to be removed consider using some of the other Bulk and Non Bulk delete methods.

Examples

using (var transaction = contextSession.StartNewTransaction())
{
    someRepo.Truncate(transaction);
    someOtherRepo.TruncateWithForeignKeys(transaction);
    transaction.Commit();
}

BulkSelectAndAdd & BulkSelectAndUpdate

BulkAdd

Overview

Used to insert or update many entities using data already available within the database. This prevents having to move large quantities between the application and database servers. Note that constant data can still be passed from the application server to the database server as part of these methods.

Note: Refer to the limitations further down on this page regarding the need for wrappers and specific ordering of properties when using the SelectAndX methods.

When To Use

For BulkSelectAndAdd, when many new records need to be created and these records can be composed of data that can be obtained from simple or complex queries directly on the database server.

For BulkSelectAndUpdate, when many new records need to be updated uniquely and this unique data (per record) can be composed of data that can be obtained from simple or complex queries directly on the database server.

Examples

var insertQuery =   someOtherEntityRepo
                    .FindAll(e => e.SomeProperty.StartsWith("Something"))
                    .GroupBy(e => e.SomeProperty)
                    .Select(g => new SomeEntityWrapper
                    {
                        Name = g.Key,
                        IsActive = g.Sum(e => e.SomeValue - e.SomeOtherValue) > SomeConstant
                    });

someRepo.BulkSelectAndAdd(insertQuery);
var updateQuery =   from someOtherEntity in someOtherIQueryable
                    join someEntity in someIQueryable on someOtherEntity.SomeKey equals someEntity.SomeKey
                    select new SomeEntityWrapper
                    {
                        SomeKey = someEntity.SomeKey,
                        IsActive = someOtherEntity.SomeProperty > SomeContant
                    };

someRepo.BulkSelectAndUpdate(updateQuery);

Traditional Entity Framework

BulkAdd

Overview

Standard Entity Framework ORM functionality with change tracking, lazy loading, eager loading etc. can be obtained through the Non Bulk methods mostly found on the base repo IRepository.

Methods include FindX, CountX, DeleteX, AddX (where X can refer to One or All as well as Tracked overloads) and updates which are are done implicitly through the change tracking mechanisms, without the need for a dedicated UpdateX method.

When To Use

The important thing to note about these methods are that they can result in many individual queries to the database server, which is perfectly fine for individual entities changes, but can also introduce significant delays when dealing with more than a few hundred records at a time. Whereas the bulk methods should be able to handle hundreds of thousands if not millions of records in a fraction of the time.

Examples

FindAll

var activeEntities = someRepo.FindAll(e => e.IsActive).ToList();

FindAll (with dynamic Sorting, Ordering and Paging)

var activeEntities = someRepo.FindAll(e => e.IsActive, "SomeProperty", "DESC", 100, 2).ToList();

CountAll

var noOfActiveEntities = someRepo.CountAll(e => e.IsActive);

DeleteAll

someRepo.DeleteAll(e => e.IsActive);

Update

var item = someRepo.FindOneTracked(e => e.Id == SomeId);
item.SomeProperty = "Changed Property";
contextSession.CommitChanges();

Getting Started

The topics below should give a brief introduction to the more important components of the framework. Alternatively the Bsg.Ef6.Tests project can also be seen as a mini POC showing how to setup the IOC containers, how to create custom DbContexts, how to create domain entities, configurations, context repos, entities repos and most importantly how to use the various methods of the abstract bulk repos defined in the framework.

Note: the that all the Contexts (Primary, Secondary), Entities (Alpha, Beta, One, Two etc.) and all their properties within the test project are completely arbitary ito their names.

DI & Built-In Services

The Bsg.EF6 framework includes a number of required Services, most of which can be overridden with custom implementations. All the services have a default concrete implementation corresponding to the same name (excluding the Interface "I" prefix). The services rely on the Constructor Injection convention for their DI implementations. Unless otherwise stated below, a transient lifecycle (or equivelent) is recommened.

See code the TestIocBootstrapper class in the Bsg.Ef6.Tests project, for an example of implementing the framework's services in an IOC (in this case Autofac).

Table Mapping Services####

ITableMappingsCacheService - Stores the cached values for table mappings (various mappings between DB Columns and Poco properties) for each context. This must be populated at system startup prior to calling any repo methods. This ideally should be a singleton service i.e. Singleton lifecycle.

ITableMappingsFactory - Builds a ContextTableMappings object for a specific context - used by the ITableMappingService below. Potentailly not required (see ITableMappingService).

ITableMappingService - Facade across the ITableMappingsCacheService and ITableMappingsFactory service to build and cache every discovered implementation of Ef6Context. This should be called manually after the IOC container has been setup. Alternatively ITableMappingsFactory and ITableMappingService can be ignored as long as the ITableMappingsCacheService has been populated (for every Ef6Context) at startup via some other custom code.

Timeout Services####

ITimeoutCacheService - Stores the cached values for various timeouts for each context. This must be populated at system startup prior to calling any repo methods. This ideally should be a singleton service i.e. Singleton lifecycle.

ITimeoutFactory - Builds a ContextTimeouts object for a specific context - used by the ITimeoutService below. Potentailly not required (see ITimeoutService).

ITimeoutService - Facade across the ITimeoutCacheService and ITimeoutCacheFactory service to build and cache every found discovered implementation of Ef6Context. This should be called manually after the IOC container has been setup. Alternatively ITimeoutCacheFactory and ITimeoutService can be ignored as long as the ITimeoutCacheService has been populated (for every Ef6Context) at startup via some other custom code.

Context Services####

IDbContextFactory - Builds DbContexts (and can also bind pre-generated EF Views at startup).

IDbContextSession - Wrapper around the instance of Ef6Context and thus controls its creation and destruction when required. There is generally 1 instance per Ef6Context implementation per request (or equivalent scope) to be shared amongst all Repository instances related to that Ef6Conext Scoped. Thus a Scoped lifecycle (or equivalent) is required.

IContextService - Facade across the IDbContextFactory in order to bind pre-generated EF Views for every Ef6Context implementation, in order to speed up the first actual query. This is usually called once at the application startup.

Repository Services####

IGenericRepository - Is a downstream repository which extends all of IRepository, IBulkInsertRepository and IBulkEndbaleRepository and thus includes all the Bulk and Non-Bulk repo functionality. It will be specific to a Ef6Context type and an IEntity type linked to that context.
This would normally be regsitered as an open generic in order to prevent having to specifiy each IEntity type manually when resgistring types on the IOC container. All Repositories (including the IGenericRepository) wrap around the scoped IDbContextSession which in turn manages the specific instance of Ef6Context. Alternatively, context specific repos or even entity specific repos can be created and registered by extending off of the IGenericRepository and when doing so, IGenericRepository can be ignored.

Utility Services

IDatabaseConnectionFactory - Builds SqlConnections

IConfigurationService - Retrieves app settings and connection strings from app.config.

IBulkInserterFactory - Builds a BulkInserter for a specific IEntity

Ef6Context

Extends off the standard DbContext and contains extended functionality to:

  • build the TableMapping for the specific context (discovered from within the StoreItemCollection)
  • discover and register all EntityTypeConfigurations relating to itself
  • expose the generic IDbSet, to be used by the various repos

Repository Pattern

Generic Repository

TODO

Context Repository

TODO

Entity Repository

TODO

IWrapperEntity

TODO

EntityTypeConfiguration

TODO

Transactions

TODO

app.config

TODO

Limitations

Code First

TODO

SelectAndX : Projections using IWrapperEntity

TODO

SelectAndX : Projections and order of properties

TODO

Primary Keys

TODO

Collections

TODO

SqlServer

TODO

Parallel Operations in same container scope

TODO

Nuget Package

TODO

ef6's People

Contributors

shane-posthumus avatar shanebsg avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.