EF Core In-Memory Database Not Saving To DbSet - c#

Overview
I am currently unit/integration testing my repository pattern with the in-memory database EF Core provides. I am on version 6.0.1 for the Microsoft.EntityFrameworkCore.InMemory nuget and using Visual Studio 2022. I am running into issues saving data to the database. Below I have included snippets of my code.
My data model:
public class Example : IExample
public Guid Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
My base repository class:
public class Repository<T> : IRepository<T> where T : class
private readonly DbSet<T> _dbSet;
private readonly DbContext _db;
public Repository(DbContext db)
{
_dbSet = db.Set<T>();
_db = db;
}
public virtual async Task Add(T entity)
{
await _dbSet.AddAsync(entity);
}
public virtual async Task<int> SaveAsync(CancellationToken token = default)
{
return await _db.SaveChangesAsync(token);
}
My repository class:
public class ExampleRepo : Repository<Example>
public ExampleRepo(ExampleContext db) : base(db)
{
}
My DbContext Class
I can show my IEntityConfiguration class for the ExampleBuilder shown below if it is needed but I don't believe that to be the problem.
public class ExampleContext : DbContext
private readonly IHttpContextAccessor? _httpContextAccessor;
public ExampleContext(DbContextOptions<ExampleContext> options) : base(options)
{
if (options == null) throw new ArgumentNullException(nameof(options));
}
public ExampleContext(DbContextOptions<ExampleContext> options, IHttpContextAccessor httpContextAccessor)
: base(options)
{
if (options == null) throw new ArgumentNullException(nameof(options));
_httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor));
}
public DbSet<Example>? Examples { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
var assembly = Assembly.GetAssembly(typeof(ExampleBuilder));
if (assembly is null)
{
throw new DataException("Could not find the assembly containing the designated model builder");
}
builder.ApplyConfigurationsFromAssembly(assembly);
foreach (var entity in builder.Model.GetEntityTypes())
{
entity.SetSchema("dbo");
}
}
public override Task<int> SaveChangesAsync(CancellationToken token = default)
{
foreach (var entry in ChangeTracker.Entries()
.Where(x => x.State is EntityState.Added or EntityState.Modified or EntityState.Deleted))
{
var user = _httpContextAccessor?.HttpContext?.User?.Identity?.Name ?? "User";
entry.Property("ModifiedBy").CurrentValue = user;
if (entry.State == EntityState.Added)
{
entry.Property("CreatedBy").CurrentValue = user;
}
if (entry.State != EntityState.Deleted) continue;
entry.State = EntityState.Modified;
entry.Property("IsActive").CurrentValue = false;
}
return base.SaveChangesAsync(token);
}
My DbContext factory method:
private ExampleContext GenerateDbContext()
{
var options = new DbContextOptionsBuilder<ExampleContext>()
.UseInMemoryDatabase(Guid.NewGuid().ToString())
.Options;
return new ExampleContext(options);
}
My unit/integration test utilizing xUnit and NET6.0
[Fact]
public async Task GetAllEntities_ShouldReturnEntities_WhenEntitiesExist()
{
// Arrange
// I used Bogus nuget for single source for generating valid models
var entity = ExampleFaker.GetModelFaker()
.Generate();
await using var context = GenerateDbContext();
var repo = new ExampleRepo(context);
await repo.Add(entity);
var changes = await repo.SaveAsync();
// Act
// Consulted this link already. Bottom answer is most related
//https://stackoverflow.com/questions/46184937/dbcontext-not-returning-local-objects
var response = await repo.GetAll();
// Assess
TestOutputHelper.WriteLine($"Added entity to repository: {entity.ToJson()}");
TestOutputHelper.WriteLine("Expected entities saved: 1");
TestOutputHelper.WriteLine($"Actual entities saved: {changes}");
TestOutputHelper.WriteLine($"Response: {response?.ToJson()}");
// Assert
Assert.Equal(1, changes);
Assert.NotNull(response);
Assert.NotEmpty(response);
Assert.IsType<List<Example>>(response.ToList());
}
Analysis & Issue
The changes variable returns 1 so I interpret this as EF does not have any issue with my model as well as I would think it successfully saved my model in the in-memory database. However, during my GetAll retrieval, no data is returned. When I debug and look into the repository private members, it shows the DbSet is empty so it is not the GetAll method causing the issue either. Since this is also just within the scope of the unit test, I don't think my Program.cs configuration has anything to do with the issue I am seeing. I have been looking at this for quite a while and can't figure out the small detail I am probably missing for the life of me.
Thank you for your help in advance.

Related

EF Core in-memory database generate System.InvalidOperationException when testing an update operation

I got the following error when I try to test an update operation using Entity Framework core:
System.InvalidOperationException : The instance of entity type 'Companies' cannot be tracked because another instance with the key value '{Id: 1}' is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached.
After doing some research, I tried everything that I found:
Create in scope DB context
deattach and attached the object I want to update from the DB context
Return the object to be updated using "AsNoTracking()" , my repository actually do this.
For the testing I am using EF in-memmory database with it fixture, I am using XUnit and .NET 5.
Can I get any help with this please?
Here is my code:
// The repository I am trying to test
public class RepositoryBase<T> : ICrudRepository<T> where T : class, IModel
{
protected PrjDbContext DatabaseContext { get; set; }
public RepositoryBase(PrjDbContext databaseContext) => DatabaseContext = databaseContext;
protected IQueryable<T> FindAll() => DatabaseContext.Set<T>().AsNoTracking();
protected IQueryable<T> FindBy(Expression<Func<T, bool>> expression) => DatabaseContext.Set<T>().Where(expression).AsNoTracking();
public void Create(T entity) => DatabaseContext.Set<T>().Add(entity);
public void Update(T entity) => DatabaseContext.Set<T>().Update(entity);
public void Delete(T entity) => DatabaseContext.Set<T>().Remove(entity);
public async Task<IEnumerable<T>> ReadAllAsync() => await FindAll().ToListAsync().ConfigureAwait(false);
public async Task<T> ReadByIdAsync(int id) => await FindBy(entity => entity.Id.Equals(id)).FirstOrDefaultAsync().ConfigureAwait(false);
}
//The Database context
public partial class PrjDbContext : DbContext
{
public PrjDbContext()
{
}
public PrjDbContext(DbContextOptions<PrjDbContext> options)
: base(options)
{
}
public virtual DbSet<Companies> Companies { get; set; }
}
// This is my fixture with the in-memory Database
public sealed class PrjSeedDataFixture : IDisposable
{
public PrjDbContext DbContext { get; }
public PrjSeedDataFixture(string name)
{
string databaseName = "PrjDatabase_" + name + "_" + DateTime.Now.ToFileTimeUtc();
DbContextOptions<PrjDbContext> options = new DbContextOptionsBuilder<PrjDbContext>()
.UseInMemoryDatabase(databaseName)
.EnableSensitiveDataLogging()
.Options;
DbContext = new PrjDbContext(options);
// Load Companies
DbContext.Companies.Add(new Companies { Id = 1, Name = "Customer 1", Status = 0, Created = DateTime.Now, LogoName = "FakeLogo.jpg", LogoPath = "/LogoPath/SecondFolder/", ModifiedBy = "Admin" });
DbContext.Companies.AsNoTracking();
DbContext.SaveChanges();
}
public void Dispose()
{
DbContext.Dispose();
}
}
The test method "Update_WhenCalled_UpdateACompanyObject", is not working for me.
// And finally, this is my test class, Create_WhenCalled_CreatesNewCompanyObject pass the test, but Update_WhenCalled_UpdateACompanyObject isn't passing the test.
public class RepositoryBaseCompanyTests
{
private Companies _newCompany;
private PrjDbContext _databaseContext;
private RepositoryBase<Companies> _sut;
public RepositoryBaseCompanyTests()
{
_newCompany = new Companies {Id = 2};
_databaseContext = new PrjSeedDataFixture("RepositoryBase").DbContext;
_sut = new RepositoryBase<Companies>(_databaseContext);
}
[Fact]
public void Create_WhenCalled_CreatesNewCompanyObject()
{
//Act
_sut.Create(_newCompany);
_databaseContext.SaveChanges();
//Assert
Assert.Equal(2, _databaseContext.Companies.Where( x => x.Id == 2).FirstOrDefault().Id);
}
[Fact]
public async void Update_WhenCalled_UpdateACompanyObject()
{
//Arrange
var company = await _sut.ReadByIdAsync(1);
company.Name = "Customer 2";
//_databaseContext.Entry(company).State = EntityState.Detached;
//_databaseContext.Attach(company);
//_databaseContext.Entry(company).State = EntityState.Modified;
//Act
_sut.Update(company);
await _databaseContext.SaveChangesAsync();
//Assert
Assert.Equal("Customer 2", _databaseContext.Companies.Where(x => x.Id == 1).FirstOrDefault().Name);
}
}
If you are using EF Core 5.0 then call DbContext.ChangeTracker.Clear() (or go through DbContext.Entries collection and set state to Detached for earlier ones) after DbContext.SaveChanges(); in PrjSeedDataFixture ctor. Adding/Updating an entry makes it tracked and you are reusing the context that created an entry with Id = 1, so when _sut.Update(company); is called it will try to track it again (since ReadByIdAsync should return an untracked one).
P.S.
Adding an extra repository abstraction layer around EF can be considered as antipattern (because EF already implements repository/UoW patterns) and the issue you are having can be one of the examples of why that is true and why this abstraction can be a leaky one. So if you still decide that having one is a good idea - you need to proceed with caution.

Repository pattern and change log implementation

I have API built with .net core 2, and I am trying to implement change log feature.
I have done basic part, but I am not sure if it's a best way for doing this.
Here is my EntityBaseRepository
public class EntityBaseRepository<T> : IEntityBaseRepository<T> where T : class, IFullAuditedEntity, new()
{
private readonly ApplicationContext context;
public EntityBaseRepository(ApplicationContext context)
{
this.context = context;
}
public virtual IEnumerable<T> items => context.Set<T>().AsEnumerable().OrderByDescending(m => m.Id);
public virtual T this[int id] => context.Set<T>().FirstOrDefault(m => m.Id == id);
public virtual T GetSingle(int id) => context.Set<T>().FirstOrDefault(x => x.Id == id);
public virtual T Add(T entity) => Operations(entity: entity, state: EntityState.Added);
public virtual T Update(T entity) => Operations(entity: entity, state: EntityState.Modified);
public virtual T Delete(T entity) => Operations(entity: entity, state: EntityState.Deleted);
public virtual T Operations(T entity, EntityState state)
{
EntityEntry dbEntityEntry = context.Entry<T>(entity);
if (state == EntityState.Added)
{
entity.CreationDateTime = DateTime.UtcNow;
entity.CreationUserId = 1;
context.Set<T>().Add(entity);
dbEntityEntry.State = EntityState.Added;
}
else if (state == EntityState.Modified)
{
entity.LastModificationDateTime = DateTime.UtcNow;
entity.LastModificationUserId = 1;
var local = context.Set<T>().Local.FirstOrDefault(entry => entry.Id.Equals(entity.Id));
if (local != null)
{
context.Entry(local).State = EntityState.Detached;
}
dbEntityEntry.State = EntityState.Modified;
}
else if (state == EntityState.Deleted)
{
entity.DeletionFlag = true;
entity.DeletionUserId = 1;
entity.DeletionDateTime = DateTime.UtcNow;
dbEntityEntry.State = EntityState.Modified;
}
return entity;
}
Here is one of my controller.
[Produces("application/json")]
[Route("api/Item")]
public class ItemController : Controller
{
private readonly IItemRepository repository;
private readonly IChangeLogRepository changeLogRepository;
private readonly IMapper mapper;
public ItemController(IItemRepository repository, IChangeLogRepository _changeLogRepository, IMapper mapper)
{
this.repository = repository;
this.changeLogRepository = _changeLogRepository;
this.mapper = mapper;
}
[HttpPost]
public IActionResult Post([FromBody]ItemDto transactionItemDto)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var item = repository.Add(mapper.Map<ItemDto, Item>(source: transactionItemDto));
repository.Commit();
ChangeLog log = new ChangeLog()
{
Log = "New Item Added"
};
changeLogRepository.Add(log);
changeLogRepository.Commit();
return new OkObjectResult(mapper.Map<Item, ItemDto>(source: item));
}
}
if you see in controller, I have added one item, and commited it, then I prepared log for that insertion, added and commited it.
Now, I have few questions, like
I have to commit my transaction twice, is there any way I can optimize it? I don't know if I can handle it on EntityBaseRepository or not.
I also want to check each property, if it gets changed or not. I want to log that to if it's changed. what would be the best way to handle it?
It would be great if anyone can help me with this. really appreciate. thanks.
You can use Action filters for a changelog Like
using System;
public class TrackMyChange : IActionFilter
{
private readonly string _chengeMessage;
private readonly IChangeLogRepository _changeLogRepository;
public TrackMyChange(string changeMessage,IChangeLogRepository changeLogRepository)
{
this._changeLogRepository = changeLogRepository;
this._chengeMessage = chengeMessage;
}
public void OnActionExecuting(ActionExecutingContext context)
{
// Do something before the action executes.
}
public void OnActionExecuted(ActionExecutedContext context)
{
// Do something after the action executes.
ChangeLog log = new ChangeLog()
{Log = this._chengeMessage};
changeLogRepository.Add(log);
changeLogRepository.Commit();
}
}
In your controller, you can use it before actions you want to log like
[TrackMyChange("Your change log here")]
public IActionResult Post()
{
}
Reference :
Action Filter Attributes in .NET core
DbContext is shared between multiple repositories within the same HTTP request scope. You won't need UoW. Just try use one Commit() and see if all changes are saved in one transaction.
https://learn.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/infrastructure-persistence-layer-implemenation-entity-framework-core
Use yourDbContext.Entry(your_entity_obj).State to get entity state. Don't log if its state is EntityState.Unchanged.
https://learn.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.entitystate?view=efcore-2.1

Entity Framework mocking requires global context

I have recently began to dig into Entity Framework unit-testing with Entity Framework 6 mocking.
I have noticed the following thing:
Entity Framework mocking forces me to create a global context in my BL class, for example:
public class RefundRepayment : IDisposable
{
protected DbContext _dbContext = new DbContext();
/* more properties and class code */
public void Dispose()
{
_dbContext.Dispose();
}
}
I can't quite figure it out, as I'd rather implement the using statement in every method in order to deal with the DbContext, my code will look like:
public class RefundRepayment
{
/* more properties and class code */
public void AccessDb()
{
using(DbContext dbContext = new DbContext())
{
/* db code here */
}
}
}
Is there any specific reason why should we initialize a global context instead of implementing the using statement?
First off, you need to be using DI (via ninject, Unity, Core, etc) to pull this off.
Let me show you a simple sample of an EF GetAll() testing my MVC controller.
[Fact]
public void GetAllOk()
{
// Arrange
// Act
var result = _controller.GetAll() as OkObjectResult;
// Assert
Assert.NotNull(result);
var recordList = result.Value as List<DTO.Account>;
Assert.NotNull(recordList);
Assert.Equal(4, recordList.Count);
}
It relies on this startup code...
public class AccountsControllerTests
{
DatabaseFixture _fixture;
AccountsControllerV1 _controller;
public AccountsControllerTests(DatabaseFixture fixture)
{
_fixture = fixture;
_controller = new AccountsControllerV1(_fixture._uow);
}
What is DatabaseFixture? Glad you asked...
public class DatabaseFixture : IDisposable
{
public ApplicationDbContext _context;
public DbContextOptions<ApplicationDbContext> _options;
public IUoW _uow;
public DatabaseFixture()
{
var x = Directory.GetCurrentDirectory();
var config = new ConfigurationBuilder()
.AddJsonFile("appsettings.Tests.json", optional : true)
.Build();
_options = new DbContextOptionsBuilder<ApplicationDbContext>()
.UseInMemoryDatabase(databaseName: "ProviderTests")
.Options;
_context = new ApplicationDbContext(_options);
_context.Database.EnsureCreated();
Initialize();
_uow = new UoW(_context);
}
private void Initialize()
{
_context.Accounts.Add(new Entities.Account() { AccountNumber = "Number 1", AccountID = "", AccountUniqueID = "" });
_context.Accounts.Add(new Entities.Account() { AccountNumber = "Number 2", AccountID = "", AccountUniqueID = "" });
_context.Accounts.Add(new Entities.Account() { AccountNumber = "Number 3", AccountID = "", AccountUniqueID = "" });
_context.Accounts.Add(new Entities.Account() { AccountNumber = "Number 4", AccountID = "", AccountUniqueID = "" });
_context.SaveChanges();
}
public void Dispose()
{
// Clean Up
_context.Database.EnsureDeleted();
}
}
[CollectionDefinition("Database Collection")]
public class DatabaseCollection : ICollectionFixture<DatabaseFixture>
{
}
A few definitions used in the above code. I used a Unit of Work Pattern that contains references to all my EF repositories. I kept Entity (Database) classes and DTO (Data Transfer Object) Classes separate. I used an in-memory replacement for the EF database that I initialize at the beginning of each run and/or test so that my data is always known. I inject the Database Fixture into my test class (not each test) so I am not creating/destroying constantly. Then I create my controller passing in my database UoW definition.
You're real controller requires injection of the UoW container you've created with the real database. You are merely substituting a controlled database environment for your test.
public AccountsControllerV1(IUoW uow)
{
_uow = uow;
}
And yes, I use versioning for the sharp-eyed. And yes, this is a Core 2 example. Still applicable for EF 6, just need 3rd party DI ;)
And the controller method I am testing?
[HttpGet("accounts", Name ="GetAccounts")]
public IActionResult GetAll()
{
try
{
var recordList = _uow.Accounts.GetAll();
List<DTO.Account> results = new List<DTO.Account>();
if (recordList != null)
{
results = recordList.Select(r => Map(r)).ToList();
}
log.Info($"Providers: GetAccounts: Success: {results.Count} records returned");
return Ok(results);
}
catch (Exception ex)
{
log.Error($"Providers: GetAccounts: Failed: {ex.Message}");
return BadRequest($"Providers: GetAccounts: Failed: {ex.Message}");
}
}

In Memory Database with.Net Core not adding data to entity collection

I am creating xunit test with EF Core 2.0.0 and InMemory 2.0.0. I noticed that the entities are not being added in the context. However it is being added at context..Local
Below is the snippet of the code
public UnitOfWorkTest()
{
_appointment = new Appointment
{
AppointmentType = AppointmentTypes.EyeTest,
AppProgress = Appointment.Confirmed,
BranchIdentifier = "MEL",
DateAdded = DateTime.Now,
Duration = 30,
Resid = "KAI",
};
}
public MyDbContext InitContext()
{
var options = new DbContextOptionsBuilder<MyDbContext>()
.UseInMemoryDatabase("Add_writes_to_database")
.Options;
return new MyDbContext(options);
}
public async Task UnitOfWork_Transaction_Test()
{
using (var context = InitContext())
{
using (var unitOfWork = new UnitOfWork(context))
{
context.Appointment.Add(_appointment);
await unitOfWork.Commit();
Assert.True(context.Appointment.Local.Count == 1);
}
}
}
Unit of Work
public sealed class UnitOfWork : IUnitOfWork
{
private IDbContext _dbContext;
public UnitOfWork(IDbContext context)
{
_dbContext = context;
}
public async Task<int> Commit()
{
// Save changes with the default options
return await _dbContext.SaveChangesAsync();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (disposing)
{
if (_dbContext != null)
{
_dbContext.Dispose();
_dbContext = null;
}
}
}
}
IDbContext
public interface IDbContext : IDisposable
{
DbSet<TEntity> Set<TEntity>() where TEntity : class;
EntityEntry<TEntity> Entry<TEntity>(TEntity entity) where TEntity : class;
EntityEntry Entry(object entity);
Task<int> SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken));
}
context.Appointment always return empty list/null but I can see the added entity in context.Appointment.Local
Any idea why this happens? How do I get the entity added in Appointment collection and not in Appointment.Local collection?
After this line context.Appointment.Add(_appointment); try to save changes in your context context.SaveChanges().I hope it will help.
In-memory database is faking a test double. Your current test relies on the implementation details of "DbSet<T> properties" within this test double.
I think implementation details is the answer to why Set<T>() works inplace:
Assert.True(context.Set<Appointment>().Count == 1);
DbSet<T> properties are there for convenience, rather than to implement data access. It is not even obligatory to have - all of - them in the context class (until you provide navigation properties in entity classes).
You can also check: Using DbContext Set<T>() instead of exposing on the context for clarification.

EF4.1 Code First DbContext: The operation cannot be completed because the DbContext has been disposed

I have a controller action that gets invoked directly, but throws this error:
The operation cannot be completed because the DbContext has been disposed.
I have only found solutions online regarding deferred excecution, but I don't think that applies here, because everywhere I use the context (in this instance) I call either .ToList() or .FirstOrDefault(). Here is my code:
CONTROLLER CONTENT
private IUnitOfWork UnitOfWork;
public MyFavouritesController(
IAccountServices accountServices,
IUnitOfWork unitOfWork
)
{
AccountServices = accountServices;
UnitOfWork = unitOfWork;
}
public ActionResult Index()
{
int? id = AccountServices.GetCurrentUserId();
if (!id.HasValue)
{
return RedirectToAction("Login", "Account", new { ReturnUrl = this.HttpContext.Request.Url.AbsolutePath });
}
var user = UnitOfWork.UserRepo.Get(id.Value, "Favourites", "Favourites.County", "Favourites.Country");
//THE ABOVE CALL GETS THE ERROR
//.....
return View();
}
REPOSITORY BASE CLASS
public class RepositoryBase<C, T> : IDisposable
where C:DbContext, new()
where T : ModelBase
{
private DbContext _context;
public DbContext Context
{
get
{
if (_context == null)
{
_context = new C();
this.AllowSerialization = true;
}
return _context;
}
set
{
_context = value;
}
}
public virtual T Get(int Id, params string[] includes)
{
if (Id > 0)
{
var result = Context.Set<T>().Where(t => t.Id == Id);
foreach (string includePath in includes)
{
result = result.Include(includePath);
}
return result.FirstOrDefault(); //This is where the error occurs.
}
else
{
throw new ApplicationException("Id is zero (0).");
}
}
//... (More CRUD methods)
public void Dispose()
{
if (Context != null)
{
Context.Dispose(); //Debugger never hits this before the error
}
}
}
UNIT OF WORK CLASS
public class UnitOfWork:IUnitOfWork
{
public UnitOfWork(
//... DI of all repos
IUserRepository userRepo
)
{
//... save repos to an local property
UserRepo = userRepo;
//create a new instance of the context so that all the repo's have access to the same DbContext
Context = new Context();
//assign the new context to all the repo's
//...
UserRepo.Context = Context;
}
public Context Context { get; set; }
public IUserRepository UserRepo { get; set; }
//... (some more repositories)
public void Dispose()
{
Context.Dispose(); //THIS IS NOT HIT AT ALL
}
}
LASTLY, THE MODEL CONTAINER HAS THIS LINE
_Instance.RegisterType<IUnitOfWork, UnitOfWork>(new PerThreadLifetimeManager());
As you can see, the index action will recieve a new instance of UnitOfWork which contains a new DbContext object. But at the first call to this context, it throws the above error. This pattern works everywhere else in my code.
Thanks
UPDATE
The answer below was to use a perRequestLifetimeManager. Here is the implimentation of one in unity:
public class HttpRequestLifetimeManager : LifetimeManager
{
private string _key = Guid.NewGuid().ToString();
public override object GetValue()
{
if (HttpContext.Current != null && HttpContext.Current.Items.Contains(_key))
return HttpContext.Current.Items[_key];
else
return null;
}
public override void RemoveValue()
{
if (HttpContext.Current != null)
HttpContext.Current.Items.Remove(_key);
}
public override void SetValue(object newValue)
{
if (HttpContext.Current != null)
HttpContext.Current.Items[_key] = newValue;
}
}
I noticed you're using a PerThreadLifetimeManager to control the creation and disposal of your unit of work class. You should probably change it to something like PerRequestLifetimeManager if your IoC container supports that.
Its because your are disposing the Unit Of Work, after wich you are requesting your data, store your data in a Variable after the query then you can release the Unit Of Work instance as well.

Categories