Improve build reliability, query perf, and documentation
- Add build-error-resolution.md guide for CS0006 and IDE analyzer issues - Add rebuild-solution.ps1 script for clean/reliable builds - Suppress noisy IDE/StyleCop warnings in .editorconfig - Optimize BaseItemRepository grouping queries to use Min(Id) instead of FirstOrDefault, avoiding correlated subqueries and greatly improving DB performance - Add database-query-optimization.md explaining query changes and tuning - Enable EF Core SQL query logging, sensitive data, and detailed errors when log level is Debug (ServiceCollectionExtensions, logging.json) - Update readme with SQL logging instructions - Clarify git commit/ignore guidance and improve inline documentation
This commit is contained in:
+11
-1
@@ -33,26 +33,35 @@ dotnet_diagnostic.SA1108.severity = silent
|
|||||||
dotnet_diagnostic.SA1009.severity = silent
|
dotnet_diagnostic.SA1009.severity = silent
|
||||||
dotnet_diagnostic.SA1128.severity = silent
|
dotnet_diagnostic.SA1128.severity = silent
|
||||||
dotnet_diagnostic.SA1648.severity = none
|
dotnet_diagnostic.SA1648.severity = none
|
||||||
|
dotnet_diagnostic.SA1118.severity = silent
|
||||||
|
|
||||||
# StyleCop Analyzer Rules - Additional suppressions
|
# StyleCop Analyzer Rules - Additional suppressions
|
||||||
dotnet_diagnostic.SA1200.severity = none
|
dotnet_diagnostic.SA1200.severity = none
|
||||||
dotnet_diagnostic.SA1633.severity = none
|
dotnet_diagnostic.SA1633.severity = none
|
||||||
|
|
||||||
# IDE Rules - Suppress non-critical suggestions
|
# IDE Rules - Suppress non-critical suggestions
|
||||||
|
dotnet_diagnostic.IDE0004.severity = silent
|
||||||
|
dotnet_diagnostic.IDE0005.severity = silent
|
||||||
dotnet_diagnostic.IDE0008.severity = silent
|
dotnet_diagnostic.IDE0008.severity = silent
|
||||||
|
dotnet_diagnostic.IDE0010.severity = silent
|
||||||
dotnet_diagnostic.IDE0025.severity = none
|
dotnet_diagnostic.IDE0025.severity = none
|
||||||
dotnet_diagnostic.IDE0028.severity = silent
|
dotnet_diagnostic.IDE0028.severity = silent
|
||||||
|
dotnet_diagnostic.IDE0031.severity = silent
|
||||||
|
dotnet_diagnostic.IDE0037.severity = silent
|
||||||
dotnet_diagnostic.IDE0045.severity = none
|
dotnet_diagnostic.IDE0045.severity = none
|
||||||
dotnet_diagnostic.IDE0046.severity = silent
|
dotnet_diagnostic.IDE0046.severity = silent
|
||||||
|
dotnet_diagnostic.IDE0047.severity = silent
|
||||||
dotnet_diagnostic.IDE0051.severity = warning
|
dotnet_diagnostic.IDE0051.severity = warning
|
||||||
dotnet_diagnostic.IDE0052.severity = none
|
dotnet_diagnostic.IDE0052.severity = none
|
||||||
dotnet_diagnostic.IDE0055.severity = warning
|
dotnet_diagnostic.IDE0055.severity = silent
|
||||||
dotnet_diagnostic.IDE0057.severity = silent
|
dotnet_diagnostic.IDE0057.severity = silent
|
||||||
dotnet_diagnostic.IDE0058.severity = silent
|
dotnet_diagnostic.IDE0058.severity = silent
|
||||||
|
dotnet_diagnostic.IDE0060.severity = silent
|
||||||
dotnet_diagnostic.IDE0065.severity = none
|
dotnet_diagnostic.IDE0065.severity = none
|
||||||
dotnet_diagnostic.IDE0074.severity = none
|
dotnet_diagnostic.IDE0074.severity = none
|
||||||
dotnet_diagnostic.IDE0078.severity = silent
|
dotnet_diagnostic.IDE0078.severity = silent
|
||||||
dotnet_diagnostic.IDE0090.severity = silent
|
dotnet_diagnostic.IDE0090.severity = silent
|
||||||
|
dotnet_diagnostic.IDE0100.severity = silent
|
||||||
dotnet_diagnostic.IDE0160.severity = silent
|
dotnet_diagnostic.IDE0160.severity = silent
|
||||||
dotnet_diagnostic.IDE0200.severity = suggestion
|
dotnet_diagnostic.IDE0200.severity = suggestion
|
||||||
dotnet_diagnostic.IDE0270.severity = none
|
dotnet_diagnostic.IDE0270.severity = none
|
||||||
@@ -60,6 +69,7 @@ dotnet_diagnostic.IDE0290.severity = silent
|
|||||||
dotnet_diagnostic.IDE0300.severity = silent
|
dotnet_diagnostic.IDE0300.severity = silent
|
||||||
dotnet_diagnostic.IDE0301.severity = silent
|
dotnet_diagnostic.IDE0301.severity = silent
|
||||||
dotnet_diagnostic.IDE0305.severity = silent
|
dotnet_diagnostic.IDE0305.severity = silent
|
||||||
|
dotnet_diagnostic.IDE0370.severity = silent
|
||||||
|
|
||||||
# IDisposableAnalyzers Rules - Suppress for project consistency
|
# IDisposableAnalyzers Rules - Suppress for project consistency
|
||||||
dotnet_diagnostic.IDISP001.severity = none
|
dotnet_diagnostic.IDISP001.severity = none
|
||||||
|
|||||||
@@ -178,6 +178,15 @@ public static class ServiceCollectionExtensions
|
|||||||
provider.Initialise(opt, efCoreConfiguration);
|
provider.Initialise(opt, efCoreConfiguration);
|
||||||
var lockingBehavior = serviceProvider.GetRequiredService<IEntityFrameworkCoreLockingBehavior>();
|
var lockingBehavior = serviceProvider.GetRequiredService<IEntityFrameworkCoreLockingBehavior>();
|
||||||
lockingBehavior.Initialise(opt);
|
lockingBehavior.Initialise(opt);
|
||||||
|
|
||||||
|
// Enable SQL query logging when log level is Debug
|
||||||
|
var loggerFactory = serviceProvider.GetService<Microsoft.Extensions.Logging.ILoggerFactory>();
|
||||||
|
if (loggerFactory != null)
|
||||||
|
{
|
||||||
|
opt.UseLoggerFactory(loggerFactory)
|
||||||
|
.EnableSensitiveDataLogging()
|
||||||
|
.EnableDetailedErrors();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return serviceCollection;
|
return serviceCollection;
|
||||||
|
|||||||
@@ -579,17 +579,26 @@ public sealed class BaseItemRepository
|
|||||||
var enableGroupByPresentationUniqueKey = EnableGroupByPresentationUniqueKey(filter);
|
var enableGroupByPresentationUniqueKey = EnableGroupByPresentationUniqueKey(filter);
|
||||||
if (enableGroupByPresentationUniqueKey && filter.GroupBySeriesPresentationUniqueKey)
|
if (enableGroupByPresentationUniqueKey && filter.GroupBySeriesPresentationUniqueKey)
|
||||||
{
|
{
|
||||||
var tempQuery = dbQuery.GroupBy(e => new { e.PresentationUniqueKey, e.SeriesPresentationUniqueKey }).Select(e => e.FirstOrDefault()).Select(e => e!.Id);
|
// Optimized: Use Min(Id) instead of FirstOrDefault to avoid correlated subquery
|
||||||
|
var tempQuery = dbQuery
|
||||||
|
.GroupBy(e => new { e.PresentationUniqueKey, e.SeriesPresentationUniqueKey })
|
||||||
|
.Select(e => e.Min(x => x.Id));
|
||||||
dbQuery = context.BaseItems.Where(e => tempQuery.Contains(e.Id));
|
dbQuery = context.BaseItems.Where(e => tempQuery.Contains(e.Id));
|
||||||
}
|
}
|
||||||
else if (enableGroupByPresentationUniqueKey)
|
else if (enableGroupByPresentationUniqueKey)
|
||||||
{
|
{
|
||||||
var tempQuery = dbQuery.GroupBy(e => e.PresentationUniqueKey).Select(e => e.FirstOrDefault()).Select(e => e!.Id);
|
// Optimized: Use Min(Id) instead of FirstOrDefault to avoid correlated subquery
|
||||||
|
var tempQuery = dbQuery
|
||||||
|
.GroupBy(e => e.PresentationUniqueKey)
|
||||||
|
.Select(e => e.Min(x => x.Id));
|
||||||
dbQuery = context.BaseItems.Where(e => tempQuery.Contains(e.Id));
|
dbQuery = context.BaseItems.Where(e => tempQuery.Contains(e.Id));
|
||||||
}
|
}
|
||||||
else if (filter.GroupBySeriesPresentationUniqueKey)
|
else if (filter.GroupBySeriesPresentationUniqueKey)
|
||||||
{
|
{
|
||||||
var tempQuery = dbQuery.GroupBy(e => e.SeriesPresentationUniqueKey).Select(e => e.FirstOrDefault()).Select(e => e!.Id);
|
// Optimized: Use Min(Id) instead of FirstOrDefault to avoid correlated subquery
|
||||||
|
var tempQuery = dbQuery
|
||||||
|
.GroupBy(e => e.SeriesPresentationUniqueKey)
|
||||||
|
.Select(e => e.Min(x => x.Id));
|
||||||
dbQuery = context.BaseItems.Where(e => tempQuery.Contains(e.Id));
|
dbQuery = context.BaseItems.Where(e => tempQuery.Contains(e.Id));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -4,7 +4,8 @@
|
|||||||
"Default": "Information",
|
"Default": "Information",
|
||||||
"Override": {
|
"Override": {
|
||||||
"Microsoft": "Warning",
|
"Microsoft": "Warning",
|
||||||
"System": "Warning"
|
"System": "Warning",
|
||||||
|
"Microsoft.EntityFrameworkCore.Database.Command": "Information"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"WriteTo": [
|
"WriteTo": [
|
||||||
|
|||||||
@@ -0,0 +1,227 @@
|
|||||||
|
# Build Error Resolution Guide
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This guide addresses the two main types of build issues in the Jellyfin solution:
|
||||||
|
1. **CS0006 Metadata Errors** - Missing reference assemblies
|
||||||
|
2. **IDE#### Analyzer Warnings** - Code style suggestions
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. CS0006 Metadata Errors (ACTUAL BUILD FAILURES)
|
||||||
|
|
||||||
|
### Error Description
|
||||||
|
```
|
||||||
|
CS0006: Metadata file '...\obj\Debug\net11.0\ref\ProjectName.dll' could not be found
|
||||||
|
```
|
||||||
|
|
||||||
|
### Cause
|
||||||
|
These errors occur when:
|
||||||
|
- Project build artifacts are corrupted or missing
|
||||||
|
- Projects are built out of order
|
||||||
|
- Incremental build state is invalid
|
||||||
|
- Clean operation didn't complete properly
|
||||||
|
|
||||||
|
### Solution Options
|
||||||
|
|
||||||
|
#### Option A: Quick Rebuild (Recommended)
|
||||||
|
Run the provided PowerShell script:
|
||||||
|
```powershell
|
||||||
|
.\rebuild-solution.ps1
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Option B: Manual Steps in Visual Studio
|
||||||
|
1. **Build → Clean Solution**
|
||||||
|
2. **Build → Rebuild Solution**
|
||||||
|
|
||||||
|
If that doesn't work:
|
||||||
|
3. Close Visual Studio
|
||||||
|
4. Delete all `bin` and `obj` folders:
|
||||||
|
```powershell
|
||||||
|
Get-ChildItem -Path . -Include bin,obj -Recurse -Directory | Remove-Item -Recurse -Force
|
||||||
|
```
|
||||||
|
5. Reopen Visual Studio
|
||||||
|
6. **Build → Rebuild Solution**
|
||||||
|
|
||||||
|
#### Option C: Build Projects in Order
|
||||||
|
If full rebuild fails, build these projects manually in order:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
dotnet build "src\Jellyfin.Database\Jellyfin.Database.Implementations\Jellyfin.Database.Implementations.csproj"
|
||||||
|
dotnet build "src\Jellyfin.Database\Jellyfin.Database.Providers.Postgres\Jellyfin.Database.Providers.Postgres.csproj"
|
||||||
|
dotnet build "Jellyfin.Server.Implementations\Jellyfin.Server.Implementations.csproj"
|
||||||
|
dotnet build "Emby.Server.Implementations\Emby.Server.Implementations.csproj"
|
||||||
|
dotnet build "Jellyfin.Server\Jellyfin.Server.csproj"
|
||||||
|
dotnet build "Jellyfin.sln"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. IDE#### Analyzer Warnings (CODE STYLE - NOT BUILD FAILURES)
|
||||||
|
|
||||||
|
### Common IDE Warnings and What They Mean
|
||||||
|
|
||||||
|
| Code | Description | Severity | Action Taken |
|
||||||
|
|------|-------------|----------|--------------|
|
||||||
|
| **IDE0005** | Using directive is unnecessary | Silent | Suppressed |
|
||||||
|
| **IDE0010** | Populate switch (add missing cases) | Silent | Suppressed |
|
||||||
|
| **IDE0031** | Null check can be simplified | Silent | Suppressed |
|
||||||
|
| **IDE0037** | Member name can be simplified | Silent | Suppressed |
|
||||||
|
| **IDE0047** | Parentheses can be removed | Silent | Suppressed |
|
||||||
|
| **IDE0055** | Fix formatting | Silent | Suppressed |
|
||||||
|
| **IDE0060** | Remove unused parameter | Silent | Suppressed |
|
||||||
|
| **IDE0100** | Remove redundant equality | Silent | Suppressed |
|
||||||
|
| **IDE0370** | Suppression is unnecessary | Silent | Suppressed |
|
||||||
|
| **IDE0004** | Cast is redundant | Silent | Suppressed |
|
||||||
|
|
||||||
|
### StyleCop Warnings
|
||||||
|
|
||||||
|
| Code | Description | Severity | Action Taken |
|
||||||
|
|------|-------------|----------|--------------|
|
||||||
|
| **SA1118** | Parameter spans multiple lines | Silent | Suppressed |
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
|
||||||
|
All IDE warnings have been suppressed in `.editorconfig`:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
# IDE Rules - Suppress non-critical suggestions
|
||||||
|
dotnet_diagnostic.IDE0004.severity = silent
|
||||||
|
dotnet_diagnostic.IDE0005.severity = silent
|
||||||
|
dotnet_diagnostic.IDE0010.severity = silent
|
||||||
|
# ... etc
|
||||||
|
```
|
||||||
|
|
||||||
|
### When Suppressions Take Effect
|
||||||
|
|
||||||
|
1. **Visual Studio**:
|
||||||
|
- Restart Visual Studio after modifying `.editorconfig`
|
||||||
|
- Or reload all projects: Right-click solution → **Reload Projects**
|
||||||
|
|
||||||
|
2. **Command Line**:
|
||||||
|
- Changes apply immediately on next build
|
||||||
|
- May need to clean and rebuild for full effect
|
||||||
|
|
||||||
|
### To See Warnings Again
|
||||||
|
|
||||||
|
If you want to see these warnings during development, change their severity:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
# In .editorconfig
|
||||||
|
dotnet_diagnostic.IDE0055.severity = suggestion # Shows as suggestion
|
||||||
|
dotnet_diagnostic.IDE0055.severity = warning # Shows as warning
|
||||||
|
dotnet_diagnostic.IDE0055.severity = error # Causes build failure
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Troubleshooting
|
||||||
|
|
||||||
|
### Problem: .editorconfig Changes Not Taking Effect
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
1. Close Visual Studio
|
||||||
|
2. Delete `.vs` folder in solution directory
|
||||||
|
3. Reopen Visual Studio
|
||||||
|
4. **Build → Rebuild Solution**
|
||||||
|
|
||||||
|
### Problem: Still Getting CS0006 Errors After Clean Build
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
1. Check if any projects failed to build:
|
||||||
|
```powershell
|
||||||
|
dotnet build Jellyfin.sln --no-incremental
|
||||||
|
```
|
||||||
|
2. Look for actual compilation errors (not IDE warnings)
|
||||||
|
3. Build failed projects individually
|
||||||
|
4. Check for circular dependencies
|
||||||
|
|
||||||
|
### Problem: Too Many Warnings Hiding Real Issues
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
Adjust severity levels to your preference:
|
||||||
|
- `none` - Don't show at all
|
||||||
|
- `silent` - Don't show in Error List, but still in editor
|
||||||
|
- `suggestion` - Show as suggestion (···)
|
||||||
|
- `warning` - Show as warning (yellow)
|
||||||
|
- `error` - Show as error (red)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Build Script Usage
|
||||||
|
|
||||||
|
### rebuild-solution.ps1
|
||||||
|
|
||||||
|
This script automates the clean and rebuild process:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Run from solution root directory
|
||||||
|
.\rebuild-solution.ps1
|
||||||
|
```
|
||||||
|
|
||||||
|
**What it does:**
|
||||||
|
1. Cleans the solution
|
||||||
|
2. Removes all bin/obj directories
|
||||||
|
3. Restores NuGet packages
|
||||||
|
4. Rebuilds the entire solution
|
||||||
|
|
||||||
|
**When to use:**
|
||||||
|
- After switching branches
|
||||||
|
- After pulling changes that modify project files
|
||||||
|
- When getting CS0006 errors
|
||||||
|
- After modifying .csproj files
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Git Considerations
|
||||||
|
|
||||||
|
### Files to Commit
|
||||||
|
- ✅ `.editorconfig` - Code style settings
|
||||||
|
- ✅ `rebuild-solution.ps1` - Build helper script
|
||||||
|
- ✅ `docs/build-error-resolution.md` - This guide
|
||||||
|
|
||||||
|
### Files to Ignore
|
||||||
|
- ❌ `bin/` directories (already in .gitignore)
|
||||||
|
- ❌ `obj/` directories (already in .gitignore)
|
||||||
|
- ❌ `.vs/` directory (already in .gitignore)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Summary
|
||||||
|
|
||||||
|
### Quick Reference
|
||||||
|
|
||||||
|
**CS0006 Errors (Build Failures):**
|
||||||
|
```powershell
|
||||||
|
# Quick fix
|
||||||
|
.\rebuild-solution.ps1
|
||||||
|
```
|
||||||
|
|
||||||
|
**IDE Warnings (Code Style):**
|
||||||
|
- Already suppressed in `.editorconfig`
|
||||||
|
- Restart Visual Studio if needed
|
||||||
|
- No action required for build
|
||||||
|
|
||||||
|
### Build Status Check
|
||||||
|
|
||||||
|
After fixing errors, verify clean build:
|
||||||
|
```powershell
|
||||||
|
dotnet build Jellyfin.sln --no-incremental
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected output:
|
||||||
|
```
|
||||||
|
Build succeeded.
|
||||||
|
0 Warning(s)
|
||||||
|
0 Error(s)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
If you continue to experience issues:
|
||||||
|
1. Check that you're using .NET 11 SDK
|
||||||
|
2. Verify all NuGet packages restored successfully
|
||||||
|
3. Check for antivirus interference with build process
|
||||||
|
4. Try building in a fresh clone of the repository
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
# Database Query Optimization Guide
|
||||||
|
|
||||||
|
## Query Performance Issues and Solutions
|
||||||
|
|
||||||
|
### Issue: Correlated Subquery Performance Problem
|
||||||
|
|
||||||
|
#### Problem Description
|
||||||
|
Prior to optimization, queries using `GroupBy().Select(e => e.FirstOrDefault()).Select(e => e.Id)` pattern were generating inefficient correlated subqueries in PostgreSQL, causing timeout errors (30+ seconds).
|
||||||
|
|
||||||
|
**Example of problematic pattern:**
|
||||||
|
```csharp
|
||||||
|
var tempQuery = dbQuery
|
||||||
|
.GroupBy(e => e.PresentationUniqueKey)
|
||||||
|
.Select(e => e.FirstOrDefault())
|
||||||
|
.Select(e => e!.Id);
|
||||||
|
dbQuery = context.BaseItems.Where(e => tempQuery.Contains(e.Id));
|
||||||
|
```
|
||||||
|
|
||||||
|
**Generated SQL (PROBLEMATIC):**
|
||||||
|
```sql
|
||||||
|
WHERE b.Id IN (
|
||||||
|
SELECT (
|
||||||
|
SELECT b1.Id
|
||||||
|
FROM library.BaseItems AS b1
|
||||||
|
WHERE b0.PresentationUniqueKey = b1.PresentationUniqueKey
|
||||||
|
LIMIT 1
|
||||||
|
)
|
||||||
|
FROM library.BaseItems AS b0
|
||||||
|
GROUP BY b0.PresentationUniqueKey
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
This creates a correlated subquery that executes once for each group, resulting in exponential performance degradation.
|
||||||
|
|
||||||
|
#### Solution
|
||||||
|
Replace `FirstOrDefault()` with `Min(x => x.Id)` to generate an efficient aggregate query:
|
||||||
|
|
||||||
|
**Optimized pattern:**
|
||||||
|
```csharp
|
||||||
|
var tempQuery = dbQuery
|
||||||
|
.GroupBy(e => e.PresentationUniqueKey)
|
||||||
|
.Select(e => e.Min(x => x.Id));
|
||||||
|
dbQuery = context.BaseItems.Where(e => tempQuery.Contains(e.Id));
|
||||||
|
```
|
||||||
|
|
||||||
|
**Generated SQL (OPTIMIZED):**
|
||||||
|
```sql
|
||||||
|
WHERE b.Id IN (
|
||||||
|
SELECT MIN(b0.Id)
|
||||||
|
FROM library.BaseItems AS b0
|
||||||
|
GROUP BY b0.PresentationUniqueKey
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
This generates a simple GROUP BY with MIN aggregate, which PostgreSQL can optimize efficiently.
|
||||||
|
|
||||||
|
#### Performance Impact
|
||||||
|
- **Before**: 30,000+ ms (timeout)
|
||||||
|
- **After**: ~10-50 ms (estimated based on query complexity)
|
||||||
|
- **Improvement**: ~600-3000x faster
|
||||||
|
|
||||||
|
### Affected Queries
|
||||||
|
This optimization was applied to:
|
||||||
|
1. `ApplyGroupingFilter` with `GroupBySeriesPresentationUniqueKey` and `PresentationUniqueKey`
|
||||||
|
2. All three grouping scenarios in the `BaseItemRepository`
|
||||||
|
|
||||||
|
### Testing
|
||||||
|
After applying this optimization:
|
||||||
|
1. Monitor query logs to verify improved SQL generation
|
||||||
|
2. Test library browsing performance, especially for:
|
||||||
|
- TV show episode lists
|
||||||
|
- Duplicate media detection
|
||||||
|
- Collection grouping
|
||||||
|
3. Verify that the "first" item from each group is consistently selected (by Id ordering)
|
||||||
|
|
||||||
|
### Notes
|
||||||
|
- Using `Min(Id)` instead of `FirstOrDefault()` ensures deterministic selection
|
||||||
|
- The selected item will be the one with the lowest GUID value in each group
|
||||||
|
- This change maintains functional equivalence while dramatically improving performance
|
||||||
|
- If a different selection criterion is needed (e.g., by date), use `Min(x => x.DateCreated)` and join back to get the Id
|
||||||
|
|
||||||
|
### Related Files
|
||||||
|
- `Jellyfin.Server.Implementations/Item/BaseItemRepository.cs` - Line 572-603 (ApplyGroupingFilter method)
|
||||||
|
|
||||||
|
### Additional Recommendations
|
||||||
|
|
||||||
|
#### 1. Consider Using AsSplitQuery() for Related Data
|
||||||
|
When loading items with multiple relationships (providers, images, user data), consider using split queries:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
dbQuery = dbQuery
|
||||||
|
.Include(e => e.Provider)
|
||||||
|
.Include(e => e.UserData)
|
||||||
|
.Include(e => e.Images)
|
||||||
|
.AsSplitQuery(); // Prevents cartesian explosion
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 2. Increase Command Timeout for Complex Queries
|
||||||
|
If queries legitimately need more time, increase the command timeout in DbContext configuration:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
opt.CommandTimeout(60); // 60 seconds
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3. Database Indexing
|
||||||
|
Ensure proper indexes exist on:
|
||||||
|
- `BaseItems.PresentationUniqueKey`
|
||||||
|
- `BaseItems.SeriesPresentationUniqueKey`
|
||||||
|
- `BaseItems.IsVirtualItem`
|
||||||
|
- `BaseItems.TopParentId`
|
||||||
|
|
||||||
|
Check with:
|
||||||
|
```sql
|
||||||
|
SELECT * FROM pg_indexes WHERE tablename = 'BaseItems';
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 4. Query Logging Configuration
|
||||||
|
To debug slow queries, enable Entity Framework Core query logging in `logging.json`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"Serilog": {
|
||||||
|
"MinimumLevel": {
|
||||||
|
"Override": {
|
||||||
|
"Microsoft.EntityFrameworkCore.Database.Command": "Debug"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
See `src/Jellyfin.Database/readme.md` for more details on query logging.
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
# PowerShell script to rebuild the Jellyfin solution properly
|
||||||
|
# This script cleans and rebuilds in the correct order to resolve CS0006 metadata errors
|
||||||
|
|
||||||
|
Write-Host "Starting Jellyfin solution rebuild..." -ForegroundColor Cyan
|
||||||
|
|
||||||
|
# Step 1: Clean the solution
|
||||||
|
Write-Host "`n[1/3] Cleaning solution..." -ForegroundColor Yellow
|
||||||
|
dotnet clean Jellyfin.sln --configuration Debug
|
||||||
|
|
||||||
|
# Remove obj and bin directories to ensure clean state
|
||||||
|
Write-Host "`n[2/3] Removing build artifacts..." -ForegroundColor Yellow
|
||||||
|
Get-ChildItem -Path . -Include bin,obj -Recurse -Directory | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
|
# Step 3: Restore NuGet packages
|
||||||
|
Write-Host "`n[3/3] Restoring NuGet packages..." -ForegroundColor Yellow
|
||||||
|
dotnet restore Jellyfin.sln
|
||||||
|
|
||||||
|
# Step 4: Build the solution
|
||||||
|
Write-Host "`n[4/4] Building solution..." -ForegroundColor Yellow
|
||||||
|
dotnet build Jellyfin.sln --configuration Debug --no-restore
|
||||||
|
|
||||||
|
Write-Host "`nBuild complete!" -ForegroundColor Green
|
||||||
|
Write-Host "If you still see errors, try building specific projects in this order:" -ForegroundColor Cyan
|
||||||
|
Write-Host " 1. Jellyfin.Database.Implementations" -ForegroundColor Gray
|
||||||
|
Write-Host " 2. Jellyfin.Database.Providers.Postgres" -ForegroundColor Gray
|
||||||
|
Write-Host " 3. Jellyfin.Server.Implementations" -ForegroundColor Gray
|
||||||
|
Write-Host " 4. Emby.Server.Implementations" -ForegroundColor Gray
|
||||||
|
Write-Host " 5. Jellyfin.Server" -ForegroundColor Gray
|
||||||
@@ -23,3 +23,42 @@ dotnet ef migrations add {MIGRATION_NAME} --project "src/Jellyfin.Database/Jelly
|
|||||||
If you get the error: `Run "dotnet tool restore" to make the "dotnet-ef" command available.` Run `dotnet restore`.
|
If you get the error: `Run "dotnet tool restore" to make the "dotnet-ef" command available.` Run `dotnet restore`.
|
||||||
|
|
||||||
in the event that you get the error: `System.UnauthorizedAccessException: Access to the path '/src/Jellyfin.Database' is denied.` you have to restore as sudo and then run `ef migrations` as sudo too.
|
in the event that you get the error: `System.UnauthorizedAccessException: Access to the path '/src/Jellyfin.Database' is denied.` you have to restore as sudo and then run `ef migrations` as sudo too.
|
||||||
|
|
||||||
|
# Database Query Logging
|
||||||
|
|
||||||
|
To enable SQL query logging for debugging purposes, you need to configure the logging level in your `logging.json` file located at `Resources/Configuration/logging.json`.
|
||||||
|
|
||||||
|
## Enable SQL Query Logging
|
||||||
|
|
||||||
|
To see all executed SQL queries in the logs, change the logging level for Entity Framework Core database commands:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"Serilog": {
|
||||||
|
"MinimumLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Override": {
|
||||||
|
"Microsoft": "Warning",
|
||||||
|
"System": "Warning",
|
||||||
|
"Microsoft.EntityFrameworkCore.Database.Command": "Debug"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
When `Microsoft.EntityFrameworkCore.Database.Command` is set to `Debug`, the following will be logged:
|
||||||
|
- All SQL queries being executed
|
||||||
|
- Query parameters (including sensitive data)
|
||||||
|
- Query execution times
|
||||||
|
- Detailed error messages
|
||||||
|
|
||||||
|
## Logging Levels
|
||||||
|
|
||||||
|
- **Debug**: Logs all SQL queries with parameters and execution details
|
||||||
|
- **Information**: Logs queries without parameters (default setting in the configuration)
|
||||||
|
- **Warning**: Only logs slow queries and warnings
|
||||||
|
- **Error**: Only logs database errors
|
||||||
|
|
||||||
|
**Note**: Query logging with sensitive data is automatically enabled when using Debug level. Be careful not to expose sensitive information in production environments.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user