Connection is Busy
See original GitHub issueI’ve got the following problem:
I’m using NPGSQL for the Connection to the Database. Furthermore I’m using Entity Framework Core.
This is how my Context looks like:
using System.IO;
using DatabaseLibrary.Models.Discount;
using DatabaseLibrary.Models.Gender;
using DatabaseLibrary.Models.Ranks;
using DatabaseLibrary.Models.Employee;
using DatabaseLibrary.Models.Items;
using DatabaseLibrary.Models.Settings;
using DatabaseLibrary.Models.Transaction;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
namespace DatabaseLibrary
{
// ReSharper disable once InconsistentNaming
public class PGSQLConnectionManager : DbContext
{
//Variables
private IConfiguration Configuration { get; }
//public PGSQLConnectionManager(DbContextOptions<PGSQLConnectionManager> options) : base(options)
//{
// Configuration = (new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("appsettings.Development.json").Build());
//}
public PGSQLConnectionManager()
{
Configuration = (new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("appsettings.Development.json").Build());
}
public PGSQLConnectionManager(IConfiguration configuration)
{
Configuration = configuration;
}
//Database
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.UseNpgsql(
Configuration["ConnectionStrings:PGSQLConnectionManager"]
);
//Model Sets
public DbSet<Gender> Gender { get; set; }
public DbSet<Gender2Employee> Gender2Employee { get; set; }
public DbSet<EmployeeRank> EmployeeRank { get; set; }
public DbSet<Employee> Employee { get; set; }
public DbSet<Item> Item { get; set; }
public DbSet<ItemType> ItemType { get; set; }
public DbSet<ItemType2Item> ItemType2Items { get; set; }
public DbSet<EmployeeRank2Employee> EmployeeRank2Employees { get; set; }
public DbSet<Transaction> Transactions { get; set; }
public DbSet<Transaction2Items> Transaction2Items { get; set; }
public DbSet<TransactionNonItem> TransactionNonItem { get; set; }
public DbSet<TaxSettings> TaxSettings { get; set; }
public DbSet<Discount> Discount { get; set; }
public DbSet<Transaction2Discount> Transaction2Discount { get; set; }
public DbSet<EmployeeRank2AspRole> EmployeeRank2AspRoles { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Gender>().ToTable("Gender");
modelBuilder.Entity<Gender2Employee>().ToTable("Gender2Employee");
modelBuilder.Entity<EmployeeRank>().ToTable("EmployeeRank");
modelBuilder.Entity<Employee>().ToTable("Employee");
modelBuilder.Entity<EmployeeRank2Employee>().ToTable("EmployeeRank2Employee");
modelBuilder.Entity<Item>().ToTable("Item");
modelBuilder.Entity<ItemType>().ToTable("ItemType");
modelBuilder.Entity<ItemType2Item>().ToTable("ItemType2Item");
modelBuilder.Entity<Transaction>().ToTable("Transaction");
modelBuilder.Entity<Transaction2Items>().ToTable("Transaction2Items");
modelBuilder.Entity<TransactionNonItem>().ToTable("TransactionNonItem");
modelBuilder.Entity<TaxSettings>().ToTable("TaxSettings");
modelBuilder.Entity<Discount>().ToTable("Discount");
modelBuilder.Entity<Transaction2Discount>().ToTable("Transaction2Discount");
modelBuilder.Entity<EmployeeRank2AspRole>().ToTable("EmployeeRank2AspRole");
/*
* Primary Key auto increment
*/
modelBuilder.Entity<Gender>()
.Property(g => g.GenderId)
.UseIdentityColumn();
modelBuilder.Entity<Gender2Employee>()
.Property(g => g.Gender2EmployeeId)
.UseIdentityColumn();
modelBuilder.Entity<Item>()
.Property(i => i.ItemId)
.UseIdentityColumn();
modelBuilder.Entity<ItemType>()
.Property(it => it.ItemTypeId)
.UseIdentityColumn();
modelBuilder.Entity<ItemType2Item>()
.Property(iti => iti.ItemType2ItemId)
.UseIdentityColumn();
modelBuilder.Entity<EmployeeRank>()
.Property(er => er.EmployeeRankId)
.UseIdentityColumn();
modelBuilder.Entity<EmployeeRank2Employee>()
.Property(ere => ere.EmployeeRank2EmployeeId)
.UseIdentityColumn();
modelBuilder.Entity<Transaction>()
.Property(t => t.TransactionId)
.UseIdentityColumn();
modelBuilder.Entity<Transaction2Items>()
.Property(ti => ti.Transaction2ItemsId)
.UseIdentityColumn();
modelBuilder.Entity<TransactionNonItem>()
.Property(tni => tni.TransactionId)
.UseIdentityColumn();
modelBuilder.Entity<TaxSettings>()
.Property(ts => ts.TaxSettingsId)
.UseIdentityColumn();
modelBuilder.Entity<Discount>()
.Property(d => d.DiscountId)
.UseIdentityColumn();
modelBuilder.Entity<Transaction2Discount>()
.Property(t2d => t2d.Transaction2DiscountId)
.UseIdentityColumn();
modelBuilder.Entity<EmployeeRank2AspRole>()
.Property(e2a => e2a.EmployeeRank2AspRoleId)
.UseIdentityColumn();
/*
* Relations
*/
//Gender
modelBuilder.Entity<Gender2Employee>()
.HasOne<Employee>()
.WithMany()
.HasForeignKey(e => e.EmployeeId)
.HasPrincipalKey(e => e.EmployeeId);
modelBuilder.Entity<Gender2Employee>()
.HasOne<Gender>()
.WithMany()
.HasForeignKey(g => g.GenderId)
.HasPrincipalKey(g => g.GenderId);
//item
modelBuilder.Entity<ItemType2Item>()
.HasOne<Item>()
.WithMany()
.HasForeignKey(i => i.ItemId)
.HasPrincipalKey(i => i.ItemId);
modelBuilder.Entity<ItemType2Item>()
.HasOne<ItemType>()
.WithMany()
.HasForeignKey(i => i.ItemTypeId)
.HasPrincipalKey(i => i.ItemTypeId);
//transaction
//transaction2items
modelBuilder.Entity<Transaction2Items>()
.HasOne<Transaction>()
.WithMany()
.HasForeignKey(t => t.TransactionId)
.HasPrincipalKey(t => t.TransactionId);
modelBuilder.Entity<Transaction2Items>()
.HasOne<Item>()
.WithMany()
.HasForeignKey(i => i.ItemId)
.HasPrincipalKey(i => i.ItemId);
//transaction2discount
modelBuilder.Entity<Transaction2Discount>()
.HasOne<Transaction>()
.WithMany()
.HasForeignKey(t => t.TransactionId)
.HasPrincipalKey(t => t.TransactionId);
modelBuilder.Entity<Transaction2Discount>()
.HasOne<Discount>()
.WithMany()
.HasForeignKey(d => d.DiscountId)
.HasPrincipalKey(d => d.DiscountId);
//employeerank2asproleid
modelBuilder.Entity<EmployeeRank2AspRole>()
.HasOne<EmployeeRank>()
.WithMany()
.HasForeignKey(er => er.EmployeeRankId)
.HasPrincipalKey(er => er.EmployeeRankId);
}
}
}
In my Startup.cs I’m adding the context to the dependency injection like this:
//Database initialization
services.AddDbContext<PGSQLConnectionManager>(options =>
options.UseNpgsql(Configuration.GetConnectionString("PGSQLConnectionManager")));
services.AddDatabaseDeveloperPageExceptionFilter();
Now since my latest additional query I was using the Context like this:
In any .razor file I’m injecting the PGSQLConnectionManager:
@inject PGSQLConnectionManager Context
And later on in the .razor file in the @code part, I use the injected Context like this:
GetEmployee getAllEmployees = new GetEmployee(Context);
And every Class that needs a database connection is getting initialized like this:
public class GetEmployee
{
//Variables
private readonly PGSQLConnectionManager _connectionManager;
public GetEmployee(PGSQLConnectionManager context)
{
_connectionManager = context;
}
public List<Employee> GetAllEmployees()
{
try
{
//query all employees
List<Employee> allEmployees = _connectionManager.Employee.AsQueryable().ToList();
return allEmployees;
}
catch (Exception e)
{
#I know this is bad, but reporting is to come
return null;
}
}
}
And now, that I’ve done this like, >20 times I get an error: Connection is Busy
I tried using a static class and reference the PGSQLConnectionManager in there once, but then everytime I try to get the Context I get an error, that the Object has been disposed??? and can’t get accessed anymore. As far as I know, objects do not get disposed if they are in a static class. I couldn’t find where the database gets disposed in the static class thing.
So far, I think I’m using EntityFramework or the NPGSQL wrong. But I cannot find a good example, that represents my case.
Thanks ahead for any help
Issue Analytics
- State:
- Created 2 years ago
- Comments:5 (3 by maintainers)
Yeah, it explains everything, thanks. I decided to write here this example for further watchers of this thread, coz the topicstarter havent written anything about his workaround or solution
@Karmageddonium this is superficially similar to the concurrent collection modification error, but things are actually simpler. A single DbContext has a single database connection, and the foreach is already using that connection for streaming query results back. Therefore SaveChanges cannot be invoked, since the connection is already busy…