| // Licensed to the Apache Software Foundation (ASF) under one or more |
| // contributor license agreements. See the NOTICE file distributed with |
| // this work for additional information regarding copyright ownership. |
| // The ASF licenses this file to You under the Apache License, Version 2.0 |
| // (the "License"); you may not use this file except in compliance with |
| // the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| = Entity Framework 2nd Level Cache |
| |
| == Overview |
| |
| Entity Framework, as most other ORMs, can use caching on multiple levels. |
| |
| * First level caching is performed by `DbContext` on the entity level (entities are cached within corresponding `DbSet`) |
| * Second level caching is on the level of `DataReader` and holds raw query data (however, there is no out-of-the-box 2nd |
| level caching mechanism in Entity Framework 6). |
| |
| Ignite.NET provides an EF6 second level caching solution that stores data in a distributed Ignite cache. This is ideal |
| for scenarios with multiple application servers using a single SQL database via Entity Framework - cached queries are |
| shared between all machines in the cluster. |
| |
| == Installation |
| * *Binary distribution*: add a reference to `Apache.Ignite.EntityFramework.dll` |
| * *NuGet*: `Install-Package Apache.Ignite.EntityFramework` |
| |
| == Configuration |
| |
| Ignite.NET provides a custom `DbConfiguration` implementation which enables second level caching - `Apache.Ignite.EntityFramework.IgniteDbConfiguration`. |
| There is a number of ways to apply `DbConfiguration` to the EntityFramework `DbContext`. See the following MSDN document |
| for details: https://msdn.microsoft.com/en-us/library/jj680699[msdn.microsoft.com/en-us/library/jj680699, window=_blank]. |
| |
| The simplest way to implement this is to use the `[DbConfigurationType]` attribute: |
| |
| [tabs] |
| -- |
| tab:C#[] |
| [source,csharp] |
| ---- |
| [DbConfigurationType(typeof(IgniteDbConfiguration))] |
| class MyContext : DbContext |
| { |
| public virtual DbSet<Foo> Foos { get; set; } |
| public virtual DbSet<Bar> Bars { get; set; } |
| } |
| ---- |
| -- |
| |
| To customize caching behavior, create a class that inherits `IgniteDbConfiguration` and call one of the base constructors. |
| The example below shows the most custom base constructor: |
| |
| [tabs] |
| -- |
| tab:C#[] |
| [source,csharp] |
| ---- |
| private class MyDbConfiguration : IgniteDbConfiguration |
| { |
| public MyDbConfiguration() |
| : base( |
| // IIgnite instance to use |
| Ignition.Start(), |
| // Metadata cache configuration (small cache, does not tolerate data loss) |
| // Should be replicated or partitioned with backups |
| new CacheConfiguration("metaCache") |
| { |
| CacheMode = CacheMode.Replicated |
| }, |
| // Data cache configuration (large cache, holds actual query results, |
| // tolerates data loss). Can have no backups. |
| new CacheConfiguration("dataCache") |
| { |
| CacheMode = CacheMode.Partitioned, |
| Backups = 0 |
| }, |
| // Custom caching policy. |
| new MyCachingPolicy()) |
| { |
| // No-op. |
| } |
| } |
| |
| // Apply custom configuration to the DbContext |
| [DbConfigurationType(typeof(MyDbConfiguration))] |
| class MyContext : DbContext |
| { |
| ... |
| } |
| ---- |
| -- |
| |
| === Caching Policy |
| |
| The caching policy feature controls a selected caching mode, expiration, and which entity sets should be cached. With the default |
| `null` policy, all entity sets are cached in the `ReadWrite` mode with no expiration. A caching policy can be configured |
| by implementing the `IDbCachingPolicy` interface or inheriting the `DbCachingPolicy` class. The example below shows a sample implementation: |
| |
| [tabs] |
| -- |
| tab:C#[] |
| [source,csharp] |
| ---- |
| public class DbCachingPolicy : IDbCachingPolicy |
| { |
| /// <summary> |
| /// Determines whether the specified query can be cached. |
| /// </summary> |
| public virtual bool CanBeCached(DbQueryInfo queryInfo) |
| { |
| // This method is called before database call. |
| // Cache only Persons. |
| return queryInfo.AffectedEntitySets.All(x => x.Name == "Person"); |
| } |
| |
| /// <summary> |
| /// Determines whether specified number of rows should be cached. |
| /// </summary> |
| public virtual bool CanBeCached(DbQueryInfo queryInfo, int rowCount) |
| { |
| // This method is called after database call. |
| // Cache only queries that return less than 1000 rows. |
| return rowCount < 1000; |
| } |
| |
| /// <summary> |
| /// Gets the absolute expiration timeout for a given query. |
| /// </summary> |
| public virtual TimeSpan GetExpirationTimeout(DbQueryInfo queryInfo) |
| { |
| // Cache for 5 minutes. |
| return TimeSpan.FromMinutes(5); |
| } |
| |
| /// <summary> |
| /// Gets the caching strategy for a given query. |
| /// </summary> |
| public virtual DbCachingMode GetCachingMode(DbQueryInfo queryInfo) |
| { |
| // Cache with invalidation. |
| return DbCachingMode.ReadWrite; |
| } |
| } |
| ---- |
| -- |
| |
| === Caching Modes |
| |
| [cols="1,3",opts="header"] |
| |=== |
| |DbCachingMode |Description |
| |`ReadOnly`| Read-only mode, never invalidates. Database updates are ignored in this mode. Once query results have been |
| cached, they are kept in cache until expired (forever when no expiration is specified). This mode is suitable for data |
| that is not expected to change (like a list of countries and other dictionary data). |
| |`ReadWrite`| Read-write mode. Cached data is invalidated when underlying entity set changes. This is "normal" cache mode |
| which always provides correct query results. Keep in mind that this mode works correctly only when all database changes |
| are performed via DbContext with Ignite caching configured. Other database updates are not tracked. |
| |=== |
| |
| == app.config & web.config |
| |
| Ignite caching can be enabled in the config files by providing an assembly-qualified type name of `IgniteDbConfiguration` (or your class that inherits it): |
| |
| [tabs] |
| -- |
| tab:app.config[] |
| [source,xml] |
| ---- |
| <entityFramework codeConfigurationType="Apache.Ignite.EntityFramework.IgniteDbConfiguration, Apache.Ignite.EntityFramework"> |
| ...Your EF config... |
| </entityFramework> |
| ---- |
| -- |
| |
| == Advanced Configuration |
| |
| When there is no possibility to inherit `IgniteDbConfiguration` (it already inherits some other class), you can call the |
| `IgniteDbConfiguration.InitializeIgniteCaching` static method from the constructor, passing `this` as the first argument: |
| |
| [tabs] |
| -- |
| tab:C#[] |
| [source,csharp] |
| ---- |
| private class MyDbConfiguration : OtherDbConfiguration |
| { |
| public MyDbConfiguration() : base(...) |
| { |
| IgniteDbConfiguration.InitializeIgniteCaching(this, Ignition.GetIgnite(), null, null, null); |
| } |
| } |
| ---- |
| -- |