Skip to content

Commit cc45228

Browse files
authored
Merge pull request #211 from JohnCampionJr/notracking
Added NoTracking support
2 parents 1c66247 + 5803d19 commit cc45228

11 files changed

+427
-51
lines changed

src/MongoFramework/IMongoDbContext.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,8 @@ public interface IMongoDbContext
1919

2020
void SaveChanges();
2121
Task SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken));
22+
23+
void Attach<TEntity>(TEntity entity) where TEntity : class;
24+
void AttachRange<TEntity>(IEnumerable<TEntity> entities) where TEntity : class;
2225
}
2326
}

src/MongoFramework/IMongoDbSet.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,6 @@ public interface IMongoDbSet<TEntity> : IMongoDbSet, IQueryable<TEntity> where T
2929
void RemoveRange(IEnumerable<TEntity> entities);
3030
void RemoveRange(Expression<Func<TEntity, bool>> predicate);
3131
void RemoveById(object entityId);
32+
IQueryable<TEntity> AsNoTracking();
3233
}
3334
}
Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1-
namespace MongoFramework
1+
using System.Collections.Generic;
2+
3+
namespace MongoFramework
24
{
3-
public interface IMongoDbTenantContext : IMongoDbContext
4-
{
5+
public interface IMongoDbTenantContext : IMongoDbContext
6+
{
57
string TenantId { get; }
8+
void CheckEntity(IHaveTenantId entity);
9+
void CheckEntities(IEnumerable<IHaveTenantId> entity);
610
}
711
}

src/MongoFramework/MongoDbContext.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using System.Reflection;
1010
using System.Threading;
1111
using System.Threading.Tasks;
12+
using MongoFramework.Utilities;
1213

1314
namespace MongoFramework
1415
{
@@ -107,6 +108,7 @@ public virtual async Task SaveChangesAsync(CancellationToken cancellationToken =
107108
ChangeTracker.CommitChanges();
108109
CommandStaging.CommitChanges();
109110
}
111+
110112
private static async Task InternalSaveChangesAsync<TEntity>(IMongoDbConnection connection, IEnumerable<IWriteCommand> commands, WriteModelOptions options, CancellationToken cancellationToken) where TEntity : class
111113
{
112114
await EntityIndexWriter.ApplyIndexingAsync<TEntity>(connection);
@@ -131,7 +133,30 @@ public IQueryable<TEntity> Query<TEntity>() where TEntity : class
131133
var provider = new MongoFrameworkQueryProvider<TEntity>(Connection);
132134
return new MongoFrameworkQueryable<TEntity>(provider);
133135
}
136+
137+
/// <summary>
138+
/// Marks the entity as unchanged in the change tracker and starts tracking.
139+
/// </summary>
140+
/// <param name="entity"></param>
141+
public virtual void Attach<TEntity>(TEntity entity) where TEntity : class
142+
{
143+
Check.NotNull(entity, nameof(entity));
144+
ChangeTracker.SetEntityState(entity, EntityEntryState.NoChanges);
145+
}
134146

147+
/// <summary>
148+
/// Marks the collection of entities as unchanged in the change tracker and starts tracking.
149+
/// </summary>
150+
/// <param name="entities"></param>
151+
public virtual void AttachRange<TEntity>(IEnumerable<TEntity> entities) where TEntity : class
152+
{
153+
Check.NotNull(entities, nameof(entities));
154+
foreach (var entity in entities)
155+
{
156+
ChangeTracker.SetEntityState(entity, EntityEntryState.NoChanges);
157+
}
158+
}
159+
135160
public void Dispose()
136161
{
137162
Dispose(true);

src/MongoFramework/MongoDbSet.cs

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ public virtual void AddRange(IEnumerable<TEntity> entities)
130130
Context.ChangeTracker.SetEntityState(entity, EntityEntryState.Added);
131131
}
132132
}
133-
133+
134134
/// <summary>
135135
/// Marks the entity for updating.
136136
/// </summary>
@@ -209,30 +209,40 @@ public async Task SaveChangesAsync(CancellationToken cancellationToken = default
209209

210210
#region IQueryable Implementation
211211

212-
protected virtual IQueryable<TEntity> GetQueryable()
212+
protected virtual IQueryable<TEntity> GetQueryable(bool trackEntities)
213213
{
214214
var queryable = Context.Query<TEntity>();
215-
var provider = queryable.Provider as IMongoFrameworkQueryProvider<TEntity>;
216-
provider.EntityProcessors.Add(new EntityTrackingProcessor<TEntity>(Context));
215+
if (trackEntities)
216+
{
217+
var provider = queryable.Provider as IMongoFrameworkQueryProvider<TEntity>;
218+
provider.EntityProcessors.Add(new EntityTrackingProcessor<TEntity>(Context));
219+
}
217220
return queryable;
218221
}
219222

220-
public Expression Expression => GetQueryable().Expression;
223+
public Expression Expression => GetQueryable(true).Expression;
221224

222-
public Type ElementType => GetQueryable().ElementType;
225+
public Type ElementType => GetQueryable(true).ElementType;
223226

224-
public IQueryProvider Provider => GetQueryable().Provider;
227+
public IQueryProvider Provider => GetQueryable(true).Provider;
225228

226229
public IEnumerator<TEntity> GetEnumerator()
227230
{
228-
return GetQueryable().GetEnumerator();
231+
return GetQueryable(true).GetEnumerator();
229232
}
230233

231234
IEnumerator IEnumerable.GetEnumerator()
232235
{
233236
return GetEnumerator();
234-
}
235-
237+
}
238+
239+
public virtual IQueryable<TEntity> AsNoTracking()
240+
{
241+
return GetQueryable(false);
242+
}
243+
236244
#endregion
237-
}
245+
246+
}
247+
238248
}

src/MongoFramework/MongoDbTenantContext.cs

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
using MongoFramework.Infrastructure.Commands;
2-
using MongoFramework.Utilities;
3-
using System;
1+
using System.Collections.Generic;
2+
using MongoFramework.Infrastructure;
3+
using MongoFramework.Infrastructure.Commands;
4+
using MongoFramework.Utilities;
45

56
namespace MongoFramework
67
{
@@ -23,5 +24,52 @@ protected override WriteModelOptions GetWriteModelOptions()
2324
{
2425
return new WriteModelOptions { TenantId = TenantId };
2526
}
27+
28+
public virtual void CheckEntity(IHaveTenantId entity)
29+
{
30+
Check.NotNull(entity, nameof(entity));
31+
32+
if (entity.TenantId != TenantId)
33+
{
34+
throw new MultiTenantException($"Entity type {entity.GetType().Name}, tenant ID does not match. Expected: {TenantId}, Entity has: {entity.TenantId}");
35+
}
36+
}
37+
38+
public virtual void CheckEntities(IEnumerable<IHaveTenantId> entities)
39+
{
40+
Check.NotNull(entities, nameof(entities));
41+
42+
foreach (var entity in entities)
43+
{
44+
CheckEntity(entity);
45+
}
46+
}
47+
48+
/// <summary>
49+
/// Marks the entity as unchanged in the change tracker and starts tracking.
50+
/// </summary>
51+
/// <param name="entity"></param>
52+
public override void Attach<TEntity>(TEntity entity) where TEntity : class
53+
{
54+
if (typeof(IHaveTenantId).IsAssignableFrom(typeof(TEntity)))
55+
{
56+
CheckEntity(entity as IHaveTenantId);
57+
}
58+
base.Attach(entity);
59+
}
60+
61+
/// <summary>
62+
/// Marks the collection of entities as unchanged in the change tracker and starts tracking.
63+
/// </summary>
64+
/// <param name="entities"></param>
65+
public override void AttachRange<TEntity>(IEnumerable<TEntity> entities) where TEntity : class
66+
{
67+
if (typeof(IHaveTenantId).IsAssignableFrom(typeof(TEntity)))
68+
{
69+
CheckEntities(entities as IEnumerable<IHaveTenantId>);
70+
}
71+
base.AttachRange(entities);
72+
}
73+
2674
}
2775
}

src/MongoFramework/MongoDbTenantSet.cs

Lines changed: 16 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -27,28 +27,8 @@ public MongoDbTenantSet(IMongoDbContext context) : base(context)
2727
{
2828
Context = context as IMongoDbTenantContext ?? throw new ArgumentException("Context provided to a MongoDbTenantSet must be IMongoDbTenantContext",nameof(context));
2929
}
30-
31-
protected virtual void CheckEntity(TEntity entity)
32-
{
33-
Check.NotNull(entity, nameof(entity));
34-
35-
if (entity.TenantId != Context.TenantId)
36-
{
37-
throw new MultiTenantException($"Entity type {entity.GetType().Name}, tenant ID does not match. Expected: {Context.TenantId}, Entity has: {entity.TenantId}");
38-
}
39-
}
40-
41-
protected virtual void CheckEntities(IEnumerable<TEntity> entities)
42-
{
43-
Check.NotNull(entities, nameof(entities));
44-
45-
foreach (var entity in entities)
46-
{
47-
CheckEntity(entity);
48-
}
49-
}
50-
51-
/// <summary>
30+
31+
/// <summary>
5232
/// Finds an entity with the given primary key value. If an entity with the given primary key value
5333
/// is being tracked by the context, then it is returned immediately without making a request to the
5434
/// database. Otherwise, a query is made to the database for an entity with the given primary key value
@@ -139,28 +119,28 @@ public override void AddRange(IEnumerable<TEntity> entities)
139119
}
140120
base.AddRange(entities);
141121
}
142-
122+
143123
public override void Update(TEntity entity)
144124
{
145-
CheckEntity(entity);
125+
Context.CheckEntity(entity);
146126
base.Update(entity);
147127
}
148128

149129
public override void UpdateRange(IEnumerable<TEntity> entities)
150130
{
151-
CheckEntities(entities);
131+
Context.CheckEntities(entities);
152132
base.UpdateRange(entities);
153133
}
154134

155135
public override void Remove(TEntity entity)
156136
{
157-
CheckEntity(entity);
137+
Context.CheckEntity(entity);
158138
base.Remove(entity);
159139
}
160140

161141
public override void RemoveRange(IEnumerable<TEntity> entities)
162142
{
163-
CheckEntities(entities);
143+
Context.CheckEntities(entities);
164144
base.RemoveRange(entities);
165145
}
166146

@@ -173,24 +153,27 @@ public override void RemoveRange(Expression<Func<TEntity, bool>> predicate)
173153

174154
#region IQueryable Implementation
175155

176-
protected override IQueryable<TEntity> GetQueryable()
156+
protected override IQueryable<TEntity> GetQueryable(bool trackEntities)
177157
{
178158
var key = Context.TenantId;
179159
var queryable = Context.Query<TEntity>().Where(c => c.TenantId == key);
180-
var provider = queryable.Provider as IMongoFrameworkQueryProvider<TEntity>;
181-
provider.EntityProcessors.Add(new EntityTrackingProcessor<TEntity>(Context));
160+
if (trackEntities)
161+
{
162+
var provider = queryable.Provider as IMongoFrameworkQueryProvider<TEntity>;
163+
provider.EntityProcessors.Add(new EntityTrackingProcessor<TEntity>(Context));
164+
}
182165
return queryable;
183166
}
184167

185168
public IQueryable<TEntity> GetSearchTextQueryable(string search)
186169
{
187170
var key = Context.TenantId;
188-
var queryable = Context.Query<TEntity>().WhereFilter(b => b.Text(search)).Where(c => c.TenantId == key);
171+
var queryable = Context.Query<TEntity>().WhereFilter(b => b.Text(search)).Where(c => c.TenantId == key);
189172
var provider = queryable.Provider as IMongoFrameworkQueryProvider<TEntity>;
190173
provider.EntityProcessors.Add(new EntityTrackingProcessor<TEntity>(Context));
191174
return queryable;
192-
}
193-
175+
}
176+
194177
#endregion
195178
}
196179
}

0 commit comments

Comments
 (0)