Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,10 @@ internal Dictionary<string, Type> GetEntityMap(OfflineDbContext context)
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to observe.</param>
/// <returns>The operation entity or null if one does not exist.</returns>
/// <exception cref="DatasyncException">Thrown if the entity ID of the provided entity is invalid.</exception>
internal async ValueTask<DatasyncOperation?> GetExistingOperationAsync(object entity, CancellationToken cancellationToken = default)
internal async ValueTask<DatasyncOperation?> GetExistingOperationAsync(EntityEntry entityEntry, CancellationToken cancellationToken = default)
{
Type entityType = entity.GetType();
EntityMetadata metadata = EntityResolver.GetEntityMetadata(entity, entityType);
Type entityType = entityEntry.Metadata.ClrType;
EntityMetadata metadata = EntityResolver.GetEntityMetadata(entityEntry.Entity, entityType);
if (!EntityResolver.EntityIdIsValid(metadata.Id))
{
throw new DatasyncException($"Entity ID for type {entityType.FullName} is invalid.");
Expand All @@ -143,7 +143,7 @@ internal Task<long> GetLastSequenceIdAsync(CancellationToken cancellationToken =
/// <returns>The operation definition.</returns>
internal DatasyncOperation GetOperationForChangedEntity(EntityEntry entry)
{
Type entityType = entry.Entity.GetType();
Type entityType = entry.Metadata.ClrType;
EntityMetadata metadata = EntityResolver.GetEntityMetadata(entry.Entity, entityType);
if (!EntityResolver.EntityIdIsValid(metadata.Id))
{
Expand Down Expand Up @@ -432,7 +432,7 @@ public async Task UpdateOperationsQueueAsync(CancellationToken cancellationToken
foreach (EntityEntry entry in entitiesInScope)
{
DatasyncOperation newOperation = GetOperationForChangedEntity(entry);
DatasyncOperation? existingOperation = await GetExistingOperationAsync(entry.Entity, cancellationToken).ConfigureAwait(false);
DatasyncOperation? existingOperation = await GetExistingOperationAsync(entry, cancellationToken).ConfigureAwait(false);
if (existingOperation is null)
{
newOperation.Sequence = Interlocked.Increment(ref sequenceId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,22 @@ public abstract class BaseTest
/// </summary>
protected static TestDbContext CreateContext(Action<DbContextOptionsBuilder<TestDbContext>> configureOptions = null)
{
SqliteConnection connection = new("Data Source=:memory:");
connection.Open();
SqliteConnection connection = CreateAndOpenConnection();
DbContextOptionsBuilder<TestDbContext> optionsBuilder = new DbContextOptionsBuilder<TestDbContext>()
.UseSqlite(connection);
configureOptions?.Invoke(optionsBuilder);
TestDbContext context = new(optionsBuilder.Options) { Connection = connection };

// Ensure the database is created.
context.Database.EnsureCreated();
return context;
}

/// <summary>
/// Creates a version of the TestDbContext backed by the specified SQLite connection.
/// </summary>
protected static TestDbContext CreateContext(SqliteConnection connection, Action<DbContextOptionsBuilder<TestDbContext>> configureOptions = null)
{
DbContextOptionsBuilder<TestDbContext> optionsBuilder = new DbContextOptionsBuilder<TestDbContext>()
.UseSqlite(connection);
configureOptions?.Invoke(optionsBuilder);
Expand All @@ -37,6 +51,16 @@ protected static TestDbContext CreateContext(Action<DbContextOptionsBuilder<Test
return context;
}

/// <summary>
/// Creates and opens an in-memory SQLite database connection.
/// </summary>
protected static SqliteConnection CreateAndOpenConnection()
{
SqliteConnection connection = new("Data Source=:memory:");
connection.Open();
return connection;
}

/// <summary>
/// Creates a response message based on code and content.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using CommunityToolkit.Datasync.TestCommon.Databases;
using Microsoft.EntityFrameworkCore;
using System.Net;
using Microsoft.Data.Sqlite;
using TestData = CommunityToolkit.Datasync.TestCommon.TestData;

namespace CommunityToolkit.Datasync.Client.Test.Offline;
Expand Down Expand Up @@ -39,7 +40,7 @@ public void GetEntityMap_Works()
public async Task GetExistingOperationAsync_InvalidId_Throws()
{
ClientMovie movie = new() { Id = "###" };
Func<Task> act = async () => _ = await queueManager.GetExistingOperationAsync(movie);
Func<Task> act = async () => _ = await queueManager.GetExistingOperationAsync(context.Entry(movie));
await act.Should().ThrowAsync<DatasyncException>();
}
#endregion
Expand Down Expand Up @@ -482,5 +483,32 @@ public async Task LLP_PushAsync_Replacement_Works()

llpContext.DatasyncOperationsQueue.Should().BeEmpty();
}

[Fact]
public async Task LLP_ModifyAfterInsertInNewContext_NoPush_ShouldUpdateOperationsQueue()
{
await using SqliteConnection connection = CreateAndOpenConnection();
string id = Guid.NewGuid().ToString("N");
await using (TestDbContext llpContext = CreateContext(connection, x => x.UseLazyLoadingProxies()))
{
ClientMovie clientMovie = new(TestData.Movies.MovieList[0].Title) { Id = id };
llpContext.Movies.Add(clientMovie);
llpContext.SaveChanges();
}

await using TestDbContext newLlpContext = CreateContext(connection, x => x.UseLazyLoadingProxies());

ClientMovie storedClientMovie = newLlpContext.Movies.First(m => m.Id == id);

// ensure that it is a lazy loading proxy and not exactly a ClientMovie
storedClientMovie.GetType().Should().NotBe(typeof(ClientMovie))
.And.Subject.Namespace.Should().Be("Castle.Proxies");

storedClientMovie.Title = TestData.Movies.MovieList[1].Title;
newLlpContext.SaveChanges();

newLlpContext.DatasyncOperationsQueue.Should().ContainSingle(op => op.ItemId == id)
.Which.EntityType.Should().NotContain("Castle.Proxies");
}
#endregion
}