Skip to content

Commit cc3fcbf

Browse files
committed
Introducing fluent API for auditing configuration. initial check in
1 parent 48ea567 commit cc3fcbf

23 files changed

+369
-259
lines changed

SampleLogMaker/Models/DbContexts.cs

-8
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
using System.Linq;
66
using System.Web;
77
using TrackerEnabledDbContext;
8-
using TrackerEnabledDbContext.Common.Fluent;
98
using TrackerEnabledDbContext.Identity;
109

1110
namespace SampleLogMaker.Models
@@ -17,13 +16,6 @@ public ApplicationDbContext()
1716
{
1817
}
1918

20-
//static ApplicationDbContext()
21-
//{
22-
// //TrackerConfiguration<Comment>
23-
// // .EnableTableTracking()
24-
// // .SkipTrackingForColumn(x => x.Id)
25-
// // .SkipTrackingForColumn(x => x.ParentBlogId);
26-
//}
2719

2820
public DbSet<Blog> Blogs { get; set; }
2921

TrackerEnabledDbContext.Common.Testing/TrackerEnabledDbContext.Common.Testing.csproj

+3-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,9 @@
5858
</When>
5959
<Otherwise>
6060
<ItemGroup>
61-
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework" />
61+
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework">
62+
<Private>False</Private>
63+
</Reference>
6264
</ItemGroup>
6365
</Otherwise>
6466
</Choose>

TrackerEnabledDbContext.Common/CommonTracker.cs

-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
using System.Data.Entity;
44
using System.Data.Entity.Infrastructure;
55
using System.Linq;
6-
using TrackerEnabledDbContext.Common.Extensions;
76
using TrackerEnabledDbContext.Common.Interfaces;
87
using TrackerEnabledDbContext.Common.Models;
98

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Data.Entity;
4+
using System.Linq;
5+
using EntityFramework.MappingAPI;
6+
using EntityFramework.MappingAPI.Extensions;
7+
using TrackerEnabledDbContext.Common.Interfaces;
8+
9+
namespace TrackerEnabledDbContext.Common.Configuration
10+
{
11+
public class DbMapping
12+
{
13+
private readonly IEntityMap _entityMap;
14+
private readonly Type _entityType;
15+
16+
public DbMapping(ITrackerContext context, Type entityType)
17+
{
18+
_entityType = entityType;
19+
_entityMap = (context as DbContext).Db(_entityType);
20+
}
21+
22+
//public string GetTableName()
23+
//{
24+
// return _entityMap.TableName;
25+
//}
26+
27+
//public string GetColumnName(string propertyName)
28+
//{
29+
// return _entityMap.Properties
30+
// .Single(x => x.PropertyName == propertyName)
31+
// .ColumnName;
32+
//}
33+
34+
public IEnumerable<PropertyConfiguerationKey> PrimaryKeys()
35+
{
36+
return _entityMap.Pks
37+
.Select(x => new PropertyConfiguerationKey(
38+
x.PropertyName,
39+
_entityType.FullName));
40+
}
41+
}
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
using System;
2+
using System.ComponentModel.DataAnnotations;
3+
using System.Linq;
4+
5+
namespace TrackerEnabledDbContext.Common.Configuration
6+
{
7+
public static class EntityTrackingConfiguration<T>
8+
{
9+
/// <summary>
10+
/// If tracking is on for a given model, this method will pause tracking.
11+
/// To resule tracking later, use ResumeTracking() method.
12+
/// </summary>
13+
public static void PauseTracking()
14+
{
15+
var newvalue = new TrackingConfigurationValue(false,
16+
TrackingConfigurationPriority.High);
17+
18+
TrackingDataStore.EntityConfigStore.AddOrUpdate(
19+
typeof(T).FullName,
20+
(key) => newvalue,
21+
(key, existingValue)=> newvalue);
22+
}
23+
24+
/// <summary>
25+
/// If tracking for a given model was paused, this method will again start tracking it.
26+
/// Note that, if tracking was never configured for this model, calling this method will have not effect.
27+
/// </summary>
28+
public static void StartTracking()
29+
{
30+
var newvalue = new TrackingConfigurationValue(true,
31+
TrackingConfigurationPriority.High);
32+
33+
TrackingDataStore.EntityConfigStore.AddOrUpdate(
34+
typeof(T).FullName,
35+
(key) => newvalue,
36+
(key, existingValue) => newvalue);
37+
}
38+
39+
public static bool IsTrackingEnabled()
40+
{
41+
TrackingConfigurationValue value = TrackingDataStore.EntityConfigStore.GetOrAdd(
42+
typeof (T).FullName,
43+
(key)=> EntityTrackingConfiguration.EntityConfigValueFactory(key, typeof(T)));
44+
45+
return value.Value;
46+
}
47+
}
48+
49+
public static class EntityTrackingConfiguration
50+
{
51+
public static bool IsTrackingEnabled(Type entityType)
52+
{
53+
TrackingConfigurationValue value = TrackingDataStore.EntityConfigStore.GetOrAdd(
54+
entityType.FullName,
55+
(key) => EntityConfigValueFactory(key, entityType)
56+
);
57+
58+
return value.Value;
59+
}
60+
61+
internal static TrackingConfigurationValue EntityConfigValueFactory(string key, Type entityType)
62+
{
63+
TrackChangesAttribute trackChangesAttribute =
64+
entityType.GetCustomAttributes(true).OfType<TrackChangesAttribute>().SingleOrDefault();
65+
bool value = trackChangesAttribute != null && trackChangesAttribute.Enabled;
66+
67+
return new TrackingConfigurationValue(value);
68+
}
69+
}
70+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace TrackerEnabledDbContext.Common.Configuration
2+
{
3+
public static class GlobalTrackingConfig
4+
{
5+
//todo:use this value
6+
public static bool Enabled { get; set; }
7+
}
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using System;
2+
3+
namespace TrackerEnabledDbContext.Common.Configuration
4+
{
5+
public class PropertyConfiguerationKey
6+
{
7+
public PropertyConfiguerationKey(string propertyName, string typeFullName)
8+
{
9+
PropertyName = propertyName;
10+
TypeFullName = typeFullName;
11+
}
12+
13+
public string PropertyName { get; }
14+
public string TypeFullName { get; }
15+
16+
public override bool Equals(object obj)
17+
{
18+
var otherEntity = (PropertyConfiguerationKey) obj;
19+
bool isNameSame = otherEntity.PropertyName.Equals(PropertyName, StringComparison.OrdinalIgnoreCase);
20+
bool isTypeSame = otherEntity.TypeFullName.Equals(TypeFullName, StringComparison.OrdinalIgnoreCase);
21+
22+
return isNameSame && isTypeSame;
23+
}
24+
25+
public override int GetHashCode()
26+
{
27+
return (PropertyName + TypeFullName).GetHashCode();
28+
}
29+
30+
public override string ToString()
31+
{
32+
return TypeFullName + "." + PropertyName;
33+
}
34+
}
35+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
using System;
2+
using System.ComponentModel.DataAnnotations;
3+
using System.Linq;
4+
using System.Linq.Expressions;
5+
using System.Reflection;
6+
using TrackerEnabledDbContext.Common.Extensions;
7+
8+
namespace TrackerEnabledDbContext.Common.Configuration
9+
{
10+
public class PropertyTrackingConfiguration<T>
11+
{
12+
public PropertyTrackingConfiguration<T> SkipProperty(Expression<Func<T, object>> property)
13+
{
14+
PropertyInfo info = property.GetPropertyInfo();
15+
var newValue = new TrackingConfigurationValue(false, TrackingConfigurationPriority.High);
16+
17+
TrackingDataStore.PropertyConfigStore.AddOrUpdate(
18+
new PropertyConfiguerationKey(info.Name, info.DeclaringType.FullName),
19+
newValue,
20+
(existingKey, existingvalue) => newValue);
21+
22+
return this;
23+
}
24+
25+
public PropertyTrackingConfiguration<T> TrackProperty(Expression<Func<T, object>> property)
26+
{
27+
PropertyInfo info = property.GetPropertyInfo();
28+
var newValue = new TrackingConfigurationValue(true, TrackingConfigurationPriority.High);
29+
TrackingDataStore.PropertyConfigStore.AddOrUpdate(
30+
new PropertyConfiguerationKey(info.Name, info.DeclaringType.FullName),
31+
newValue,
32+
(key, value) => newValue);
33+
34+
return this;
35+
}
36+
37+
public static bool IsTrackingEnabled(Expression<Func<T, object>> property)
38+
{
39+
var key = new PropertyConfiguerationKey(property.GetPropertyInfo().Name,
40+
property.GetPropertyInfo().DeclaringType.FullName);
41+
42+
string propertyName = property.GetPropertyInfo().Name;
43+
44+
var result = TrackingDataStore.PropertyConfigStore
45+
.GetOrAdd(key,
46+
(x) =>
47+
PropertyTrackingConfiguration.PropertyConfigValueFactory(propertyName, typeof(T)));
48+
49+
return result.Value;
50+
}
51+
}
52+
53+
public static class PropertyTrackingConfiguration
54+
{
55+
public static bool IsTrackingEnabled(PropertyConfiguerationKey property, Type entityType)
56+
{
57+
var result = TrackingDataStore.PropertyConfigStore
58+
.GetOrAdd(property,
59+
(x) =>
60+
PropertyConfigValueFactory(property.PropertyName, entityType));
61+
62+
return result.Value;
63+
}
64+
65+
internal static TrackingConfigurationValue PropertyConfigValueFactory(string propertyName,
66+
Type entityType)
67+
{
68+
SkipTrackingAttribute skipTrackingAttribute =
69+
entityType.GetProperty(propertyName)
70+
.GetCustomAttributes(false)
71+
.OfType<SkipTrackingAttribute>()
72+
.SingleOrDefault();
73+
74+
bool trackValue = skipTrackingAttribute == null || !skipTrackingAttribute.Enabled;
75+
76+
return new TrackingConfigurationValue(trackValue);
77+
}
78+
}
79+
80+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace TrackerEnabledDbContext.Common.Configuration
2+
{
3+
public enum TrackingConfigurationPriority
4+
{
5+
Default = 0,
6+
High = 1
7+
}
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
namespace TrackerEnabledDbContext.Common.Configuration
2+
{
3+
public class TrackingConfigurationValue
4+
{
5+
public TrackingConfigurationValue(bool value = false, TrackingConfigurationPriority priority = TrackingConfigurationPriority.Default)
6+
{
7+
Value = value;
8+
Priority = priority;
9+
}
10+
11+
public bool Value { get; private set; }
12+
public TrackingConfigurationPriority Priority { get; private set; }
13+
}
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using System.Collections.Concurrent;
2+
3+
namespace TrackerEnabledDbContext.Common.Configuration
4+
{
5+
public static class TrackingDataStore
6+
{
7+
////////////////////////// STORE /////////////////////////////
8+
9+
internal static ConcurrentDictionary<string, TrackingConfigurationValue> EntityConfigStore = new ConcurrentDictionary<string, TrackingConfigurationValue>();
10+
internal static ConcurrentDictionary<PropertyConfiguerationKey, TrackingConfigurationValue> PropertyConfigStore = new ConcurrentDictionary<PropertyConfiguerationKey, TrackingConfigurationValue>();
11+
}
12+
}
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,31 @@
11
using System.Collections.Generic;
22
using System.Data.Entity.Infrastructure;
33
using System.Linq;
4+
using TrackerEnabledDbContext.Common.Configuration;
45

56
namespace TrackerEnabledDbContext.Common.Extensions
67
{
78
public static class DbEntryExtensions
89
{
9-
public static object GetDatabaseValue(this DbEntityEntry dbEntry, string columnName)
10+
public static object GetPrimaryKeyValues(
11+
this DbEntityEntry dbEntry,
12+
List<PropertyConfiguerationKey> properties)
1013
{
11-
return dbEntry.GetDatabaseValues().GetValue<object>(columnName);
12-
}
13-
14-
public static object GetPrimaryKeyValues(this DbEntityEntry dbEntry, IEnumerable<string> columnNames)
15-
{
16-
if (columnNames.Count() == 1)
14+
if (properties.Count == 1)
1715
{
18-
return dbEntry.GetDatabaseValues().GetValue<object>(columnNames.First());
16+
return dbEntry.GetDatabaseValues().GetValue<object>(properties.Select(x=>x.PropertyName).First());
1917
}
20-
if (columnNames.Count() > 1)
18+
if (properties.Count > 1)
2119
{
2220
string output = "[";
2321

2422
output += string.Join(",",
25-
columnNames.Select(colName => { return dbEntry.GetDatabaseValues().GetValue<object>(colName); }));
23+
properties.Select(colName => dbEntry.GetDatabaseValues().GetValue<object>(colName.PropertyName)));
2624

2725
output += "]";
2826
return output;
2927
}
3028
throw new KeyNotFoundException("key not found for " + dbEntry.Entity.GetType().FullName);
3129
}
32-
33-
public static object GetCurrentValue(this DbEntityEntry dbEntry, string columnName)
34-
{
35-
return dbEntry.CurrentValues.GetValue<object>(columnName);
36-
}
3730
}
3831
}

0 commit comments

Comments
 (0)