Skip to content

Commit 617e2cd

Browse files
authored
Merge pull request #182 from JohnCampionJr/find-async
Added FindAsync and Added to TenantDbSet
2 parents 8e740a1 + 26a0992 commit 617e2cd

File tree

5 files changed

+456
-38
lines changed

5 files changed

+456
-38
lines changed

src/MongoFramework/IMongoDbSet.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ public interface IMongoDbSet<TEntity> : IMongoDbSet, IQueryable<TEntity> where T
1818
{
1919
IMongoDbContext Context { get; }
2020
TEntity Find(object id);
21+
ValueTask<TEntity> FindAsync(object id);
2122
TEntity Create();
2223
void Add(TEntity entity);
2324
void AddRange(IEnumerable<TEntity> entities);

src/MongoFramework/MongoDbSet.cs

Lines changed: 73 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -34,43 +34,79 @@ public virtual TEntity Create()
3434
var entity = Activator.CreateInstance<TEntity>();
3535
Add(entity);
3636
return entity;
37-
}
38-
39-
/// <summary>
40-
/// Finds an entity with the given primary key value. If an entity with the given primary key value
41-
/// is being tracked by the context, then it is returned immediately without making a request to the
42-
/// database. Otherwise, a query is made to the database for an entity with the given primary key value
43-
/// and this entity, if found, is attached to the context and returned. If no entity is found, then
44-
/// null is returned.
45-
/// </summary>
46-
/// <param name="id">The value of the primary key for the entity to be found.</param>
47-
/// <returns>The entity found, or null.</returns>
48-
public virtual TEntity Find(object id)
49-
{
50-
Check.NotNull(id, nameof(id));
51-
52-
var tracked = Context.ChangeTracker.GetEntryById<TEntity>(id);
53-
54-
if (tracked != null)
55-
{
56-
return tracked.Entity as TEntity;
57-
}
58-
59-
var entityDefinition = EntityMapping.GetOrCreateDefinition(typeof(TEntity));
60-
var filter = entityDefinition.CreateIdFilter<TEntity>(id);
61-
62-
var collection = Context.Connection.GetDatabase().GetCollection<TEntity>(entityDefinition.CollectionName);
63-
var cursor = collection.Find(filter);
64-
var entity = cursor.FirstOrDefault();
65-
66-
if (entity != null)
67-
{
68-
Context.ChangeTracker.SetEntityState(entity, EntityEntryState.NoChanges);
69-
}
70-
71-
return entity;
72-
}
73-
37+
}
38+
39+
/// <summary>
40+
/// Finds an entity with the given primary key value. If an entity with the given primary key value
41+
/// is being tracked by the context, then it is returned immediately without making a request to the
42+
/// database. Otherwise, a query is made to the database for an entity with the given primary key value
43+
/// and this entity, if found, is attached to the context and returned. If no entity is found, then
44+
/// null is returned.
45+
/// </summary>
46+
/// <param name="id">The value of the primary key for the entity to be found.</param>
47+
/// <returns>The entity found, or null.</returns>
48+
public virtual TEntity Find(object id)
49+
{
50+
Check.NotNull(id, nameof(id));
51+
52+
var tracked = Context.ChangeTracker.GetEntryById<TEntity>(id);
53+
54+
if (tracked != null)
55+
{
56+
return tracked.Entity as TEntity;
57+
}
58+
59+
var entityDefinition = EntityMapping.GetOrCreateDefinition(typeof(TEntity));
60+
var filter = entityDefinition.CreateIdFilter<TEntity>(id);
61+
62+
var collection = Context.Connection.GetDatabase().GetCollection<TEntity>(entityDefinition.CollectionName);
63+
var cursor = collection.Find(filter);
64+
var entity = cursor.FirstOrDefault();
65+
66+
if (entity != null)
67+
{
68+
Context.ChangeTracker.SetEntityState(entity, EntityEntryState.NoChanges);
69+
}
70+
71+
return entity;
72+
}
73+
74+
/// <summary>
75+
/// Finds an entity with the given primary key value. If an entity with the given primary key value
76+
/// is being tracked by the context, then it is returned immediately without making a request to the
77+
/// database. Otherwise, a query is made to the database for an entity with the given primary key value
78+
/// and this entity, if found, is attached to the context and returned. If no entity is found, then
79+
/// null is returned.
80+
/// </summary>
81+
/// <param name="id">The value of the primary key for the entity to be found.</param>
82+
/// <returns>The entity found, or null.</returns>
83+
public virtual async ValueTask<TEntity> FindAsync(object id)
84+
{
85+
Check.NotNull(id, nameof(id));
86+
87+
var tracked = Context.ChangeTracker.GetEntryById<TEntity>(id);
88+
89+
if (tracked != null)
90+
{
91+
return tracked.Entity as TEntity;
92+
}
93+
94+
var entityDefinition = EntityMapping.GetOrCreateDefinition(typeof(TEntity));
95+
var filter = entityDefinition.CreateIdFilter<TEntity>(id);
96+
97+
var collection = Context.Connection.GetDatabase().GetCollection<TEntity>(entityDefinition.CollectionName);
98+
var cursor = await collection.FindAsync(filter);
99+
var entity = await cursor.FirstOrDefaultAsync();
100+
101+
if (entity != null)
102+
{
103+
Context.ChangeTracker.SetEntityState(entity, EntityEntryState.NoChanges);
104+
}
105+
106+
return entity;
107+
}
108+
109+
74110
/// <summary>
75111
/// Marks the entity for insertion into the database.
76112
/// </summary>

src/MongoFramework/MongoDbTenantSet.cs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55
using System.Collections.Generic;
66
using System.Linq;
77
using System.Linq.Expressions;
8+
using System.Threading.Tasks;
9+
using MongoDB.Driver;
10+
using MongoFramework.Infrastructure;
11+
using MongoFramework.Infrastructure.Commands;
12+
using MongoFramework.Infrastructure.Mapping;
813
using MongoFramework.Utilities;
914

1015
namespace MongoFramework
@@ -43,6 +48,79 @@ protected virtual void CheckEntities(IEnumerable<TEntity> entities)
4348
}
4449
}
4550

51+
/// <summary>
52+
/// Finds an entity with the given primary key value. If an entity with the given primary key value
53+
/// is being tracked by the context, then it is returned immediately without making a request to the
54+
/// database. Otherwise, a query is made to the database for an entity with the given primary key value
55+
/// and this entity, if found, is attached to the context and returned. If no entity is found, then
56+
/// null is returned.
57+
/// </summary>
58+
/// <param name="id">The value of the primary key for the entity to be found.</param>
59+
/// <returns>The entity found, or null.</returns>
60+
public override TEntity Find(object id)
61+
{
62+
Check.NotNull(id, nameof(id));
63+
64+
var tracked = Context.ChangeTracker.GetEntryById<TEntity>(id);
65+
66+
if (tracked != null)
67+
{
68+
if ((tracked.Entity as IHaveTenantId)?.TenantId == Context.TenantId)
69+
{
70+
return tracked.Entity as TEntity;
71+
}
72+
}
73+
74+
var entityDefinition = EntityMapping.GetOrCreateDefinition(typeof(TEntity));
75+
var filter = entityDefinition.CreateIdFilter<TEntity>(id, Context.TenantId);
76+
77+
var collection = Context.Connection.GetDatabase().GetCollection<TEntity>(entityDefinition.CollectionName);
78+
var cursor = collection.Find(filter);
79+
var entity = cursor.FirstOrDefault();
80+
81+
if (entity != null)
82+
{
83+
Context.ChangeTracker.SetEntityState(entity, EntityEntryState.NoChanges);
84+
}
85+
86+
return entity;
87+
}
88+
89+
/// <summary>
90+
/// Finds an entity with the given primary key value. If an entity with the given primary key value
91+
/// is being tracked by the context, then it is returned immediately without making a request to the
92+
/// database. Otherwise, a query is made to the database for an entity with the given primary key value
93+
/// and this entity, if found, is attached to the context and returned. If no entity is found, then
94+
/// null is returned.
95+
/// </summary>
96+
/// <param name="id">The value of the primary key for the entity to be found.</param>
97+
/// <returns>The entity found, or null.</returns>
98+
public override async ValueTask<TEntity> FindAsync(object id)
99+
{
100+
Check.NotNull(id, nameof(id));
101+
102+
var tracked = Context.ChangeTracker.GetEntryById<TEntity>(id);
103+
104+
if (tracked != null)
105+
{
106+
return tracked.Entity as TEntity;
107+
}
108+
109+
var entityDefinition = EntityMapping.GetOrCreateDefinition(typeof(TEntity));
110+
var filter = entityDefinition.CreateIdFilter<TEntity>(id, Context.TenantId);
111+
112+
var collection = Context.Connection.GetDatabase().GetCollection<TEntity>(entityDefinition.CollectionName);
113+
var cursor = await collection.FindAsync(filter);
114+
var entity = await cursor.FirstOrDefaultAsync();
115+
116+
if (entity != null)
117+
{
118+
Context.ChangeTracker.SetEntityState(entity, EntityEntryState.NoChanges);
119+
}
120+
121+
return entity;
122+
}
123+
46124
public override void Add(TEntity entity)
47125
{
48126
Check.NotNull(entity, nameof(entity));

tests/MongoFramework.Tests/MongoDbSetTests.cs

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using Microsoft.VisualStudio.TestTools.UnitTesting;
1+
using Microsoft.VisualStudio.TestTools.UnitTesting;
22
using System;
33
using System.ComponentModel.DataAnnotations;
44
using System.Linq;
@@ -122,6 +122,77 @@ public void FindRequiresId()
122122
Assert.ThrowsException<ArgumentNullException>(() => dbSet.Find(null));
123123
}
124124

125+
[TestMethod]
126+
public async Task SuccessfulInsertAndFindAsync()
127+
{
128+
var connection = TestConfiguration.GetConnection();
129+
var context = new MongoDbContext(connection);
130+
var dbSet = new MongoDbSet<TestModel>(context);
131+
132+
var model = new TestModel
133+
{
134+
Description = "SuccessfulInsertAndFind"
135+
};
136+
137+
dbSet.Add(model);
138+
139+
context.SaveChanges();
140+
141+
context = new MongoDbContext(connection);
142+
dbSet = new MongoDbSet<TestModel>(context);
143+
Assert.AreEqual("SuccessfulInsertAndFind", (await dbSet.FindAsync(model.Id)).Description);
144+
Assert.AreEqual(MongoFramework.Infrastructure.EntityEntryState.NoChanges, context.ChangeTracker.GetEntry(model).State);
145+
}
146+
147+
[TestMethod]
148+
public async Task SuccessfulNullFindAsync()
149+
{
150+
var connection = TestConfiguration.GetConnection();
151+
var context = new MongoDbContext(connection);
152+
var dbSet = new MongoDbSet<TestModel>(context);
153+
154+
var model = new TestModel
155+
{
156+
Description = "SuccessfulNullFind"
157+
};
158+
159+
dbSet.Add(model);
160+
161+
context.SaveChanges();
162+
163+
Assert.IsNull(await dbSet.FindAsync("abcd"));
164+
}
165+
166+
[TestMethod]
167+
public async Task SuccessfullyFindAsyncTracked()
168+
{
169+
var connection = TestConfiguration.GetConnection();
170+
var context = new MongoDbContext(connection);
171+
var dbSet = new MongoDbSet<TestModel>(context);
172+
173+
var model = new TestModel
174+
{
175+
Id = "abcd",
176+
Description = "SuccessfullyFindTracked"
177+
};
178+
179+
dbSet.Add(model);
180+
181+
//Note: not saving, but still should be found as tracked
182+
Assert.AreEqual("SuccessfullyFindTracked", (await dbSet.FindAsync(model.Id)).Description);
183+
Assert.AreEqual(MongoFramework.Infrastructure.EntityEntryState.Added, context.ChangeTracker.GetEntry(model).State);
184+
}
185+
186+
[TestMethod]
187+
public async Task FindAsyncRequiresId()
188+
{
189+
var connection = TestConfiguration.GetConnection();
190+
var context = new MongoDbContext(connection);
191+
var dbSet = new MongoDbSet<TestModel>(context);
192+
193+
await Assert.ThrowsExceptionAsync<ArgumentNullException>(async () => await dbSet.FindAsync(null));
194+
}
195+
125196
[TestMethod]
126197
public void SuccessfullyUpdateEntity()
127198
{

0 commit comments

Comments
 (0)