Cache statistics and move its generation to importers.

This commit is contained in:
2020-09-11 00:42:24 +01:00
parent 05e7ed4783
commit 2c9814292a
9 changed files with 653 additions and 79 deletions

View File

@@ -1045,51 +1045,65 @@ namespace RomRepoMgr.Core.Workers
newMedias.Clear();
newMediasByMachine.Clear();
WorkFinished?.Invoke(this, System.EventArgs.Empty);
RomSetStat stats = ctx.RomSets.Where(r => r.Id == romSet.Id).Select(r => new RomSetStat
{
RomSetId = r.Id,
TotalMachines = r.Machines.Count,
CompleteMachines =
r.Machines.Count(m => m.Files.Count > 0 && m.Disks.Count == 0 &&
m.Files.All(f => f.File.IsInRepo)) +
r.Machines.Count(m => m.Disks.Count > 0 && m.Files.Count == 0 &&
m.Disks.All(f => f.Disk.IsInRepo)) +
r.Machines.Count(m => m.Files.Count > 0 && m.Disks.Count > 0 &&
m.Files.All(f => f.File.IsInRepo) && m.Disks.All(f => f.Disk.IsInRepo)),
IncompleteMachines =
r.Machines.Count(m => m.Files.Count > 0 && m.Disks.Count == 0 &&
m.Files.Any(f => !f.File.IsInRepo)) +
r.Machines.Count(m => m.Disks.Count > 0 && m.Files.Count == 0 &&
m.Disks.Any(f => !f.Disk.IsInRepo)) +
r.Machines.Count(m => m.Files.Count > 0 && m.Disks.Count > 0 &&
(m.Files.Any(f => !f.File.IsInRepo) ||
m.Disks.Any(f => !f.Disk.IsInRepo))),
TotalRoms = r.Machines.Sum(m => m.Files.Count) + r.Machines.Sum(m => m.Disks.Count) +
r.Machines.Sum(m => m.Medias.Count),
HaveRoms = r.Machines.Sum(m => m.Files.Count(f => f.File.IsInRepo)) +
r.Machines.Sum(m => m.Disks.Count(f => f.Disk.IsInRepo)) +
r.Machines.Sum(m => m.Medias.Count(f => f.Media.IsInRepo)),
MissRoms = r.Machines.Sum(m => m.Files.Count(f => !f.File.IsInRepo)) +
r.Machines.Sum(m => m.Disks.Count(f => !f.Disk.IsInRepo)) +
r.Machines.Sum(m => m.Medias.Count(f => !f.Media.IsInRepo))
}).FirstOrDefault();
romSet = ctx.RomSets.Find(romSet.Id);
RomSetStat oldStats = ctx.RomSetStats.Find(stats.RomSetId);
if(oldStats != null)
ctx.Remove(oldStats);
ctx.RomSetStats.Add(stats);
WorkFinished?.Invoke(this, System.EventArgs.Empty);
RomSetAdded?.Invoke(this, new RomSetEventArgs
{
RomSet = new RomSetModel
{
Id = romSet.Id,
Author = romSet.Author,
Comment = romSet.Comment,
Date = romSet.Date,
Description = romSet.Description,
Filename = romSet.Filename,
Homepage = romSet.Homepage,
Name = romSet.Name,
Sha384 = romSet.Sha384,
Version = romSet.Version,
TotalMachines = romSet.Machines?.Count ?? 0,
CompleteMachines =
romSet.Machines?.Count(m => m.Files?.Count > 0 && m.Disks == null &&
m.Files.All(f => f.File.IsInRepo)) ??
0 + romSet.Machines?.Count(m => m.Disks?.Count > 0 && m.Files == null &&
m.Disks.All(f => f.Disk.IsInRepo)) ?? 0 +
romSet.Machines?.Count(m => m.Files?.Count > 0 && m.Disks?.Count > 0 &&
m.Files.All(f => f.File.IsInRepo) &&
m.Disks.All(f => f.Disk.IsInRepo)) ?? 0,
IncompleteMachines =
romSet.Machines?.Count(m => m.Files?.Count > 0 && m.Disks == null &&
m.Files.Any(f => !f.File.IsInRepo)) ??
0 + romSet.Machines?.Count(m => m.Disks?.Count > 0 && m.Files == null &&
m.Disks.Any(f => !f.Disk.IsInRepo)) ?? 0 +
romSet.Machines?.Count(m => m.Files?.Count > 0 && m.Disks?.Count > 0 &&
(m.Files.Any(f => !f.File.IsInRepo) ||
m.Disks.Any(f => !f.Disk.IsInRepo))) ?? 0,
TotalRoms = romSet.Machines?.Sum(m => m.Files?.Count ?? 0) ??
0 + romSet.Machines?.Sum(m => m.Disks?.Count ?? 0) ??
0 + romSet.Machines?.Sum(m => m.Medias?.Count ?? 0) ?? 0,
HaveRoms = romSet.Machines?.Sum(m => m.Files?.Count(f => f.File.IsInRepo) ?? 0) ??
0 + romSet.Machines?.Sum(m => m.Disks?.Count(f => f.Disk.IsInRepo) ?? 0) ??
0 + romSet.Machines?.Sum(m => m.Medias?.Count(f => f.Media.IsInRepo) ?? 0) ?? 0,
MissRoms = romSet.Machines?.Sum(m => m.Files?.Count(f => !f.File.IsInRepo) ?? 0) ??
0 + romSet.Machines?.Sum(m => m.Disks?.Count(f => !f.Disk.IsInRepo) ?? 0) ??
0 + romSet.Machines?.Sum(m => m.Medias?.Count(f => !f.Media.IsInRepo) ?? 0) ?? 0,
Category = _category
Id = romSet.Id,
Author = romSet.Author,
Comment = romSet.Comment,
Date = romSet.Date,
Description = romSet.Description,
Filename = romSet.Filename,
Homepage = romSet.Homepage,
Name = romSet.Name,
Sha384 = romSet.Sha384,
Version = romSet.Version,
TotalMachines = stats.TotalMachines,
CompleteMachines = stats.CompleteMachines,
IncompleteMachines = stats.IncompleteMachines,
TotalRoms = stats.TotalRoms,
HaveRoms = stats.HaveRoms,
MissRoms = stats.MissRoms,
Category = romSet.Category
}
});
}

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using RomRepoMgr.Core.Aaru;
using RomRepoMgr.Core.EventArgs;
@@ -929,7 +930,7 @@ namespace RomRepoMgr.Core.Workers
bool knownMediaWasBigger = false;
if(sha256 != null)
knownMedia = _pendingMediasBySha1.TryGetValue(sha256, out dbMedia);
knownMedia = _pendingMediasBySha256.TryGetValue(sha256, out dbMedia);
if(!knownMedia &&
sha1 != null)
@@ -1183,10 +1184,44 @@ namespace RomRepoMgr.Core.Workers
_ctx.Files.AddRange(_newFiles);
_ctx.Disks.AddRange(_newDisks);
_ctx.Medias.AddRange(_newMedias);
_ctx.Database.ExecuteSqlRaw("DELETE FROM \"RomSetStats\"");
_ctx.RomSetStats.AddRange(_ctx.RomSets.OrderBy(r => r.Id).Select(r => new RomSetStat
{
RomSetId = r.Id,
TotalMachines = r.Machines.Count,
CompleteMachines =
r.Machines.Count(m => m.Files.Count > 0 && m.Disks.Count == 0 &&
m.Files.All(f => f.File.IsInRepo)) +
r.Machines.Count(m => m.Disks.Count > 0 && m.Files.Count == 0 &&
m.Disks.All(f => f.Disk.IsInRepo)) +
r.Machines.Count(m => m.Files.Count > 0 && m.Disks.Count > 0 && m.Files.All(f => f.File.IsInRepo) &&
m.Disks.All(f => f.Disk.IsInRepo)),
IncompleteMachines =
r.Machines.Count(m => m.Files.Count > 0 && m.Disks.Count == 0 &&
m.Files.Any(f => !f.File.IsInRepo)) +
r.Machines.Count(m => m.Disks.Count > 0 && m.Files.Count == 0 &&
m.Disks.Any(f => !f.Disk.IsInRepo)) +
r.Machines.Count(m => m.Files.Count > 0 && m.Disks.Count > 0 &&
(m.Files.Any(f => !f.File.IsInRepo) || m.Disks.Any(f => !f.Disk.IsInRepo))),
TotalRoms = r.Machines.Sum(m => m.Files.Count) + r.Machines.Sum(m => m.Disks.Count) +
r.Machines.Sum(m => m.Medias.Count),
HaveRoms = r.Machines.Sum(m => m.Files.Count(f => f.File.IsInRepo)) +
r.Machines.Sum(m => m.Disks.Count(f => f.Disk.IsInRepo)) +
r.Machines.Sum(m => m.Medias.Count(f => f.Media.IsInRepo)),
MissRoms = r.Machines.Sum(m => m.Files.Count(f => !f.File.IsInRepo)) +
r.Machines.Sum(m => m.Disks.Count(f => !f.Disk.IsInRepo)) +
r.Machines.Sum(m => m.Medias.Count(f => !f.Media.IsInRepo))
}));
// TODO: Refresh main view
_ctx.SaveChanges();
_newFiles.Clear();
_newDisks.Clear();
_newMedias.Clear();
}
string GetArchiveFormat(string path, out long counter)

View File

@@ -41,6 +41,7 @@ namespace RomRepoMgr.Database
public DbSet<DiskByMachine> DisksByMachines { get; set; }
public DbSet<DbMedia> Medias { get; set; }
public DbSet<MediaByMachine> MediasByMachines { get; set; }
public DbSet<RomSetStat> RomSetStats { get; set; }
public static Context Create(string dbPath)
{
@@ -160,6 +161,11 @@ namespace RomRepoMgr.Database
entity.HasOne(e => e.Media).WithMany(e => e.Machines).OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity<RomSetStat>(entity =>
{
entity.HasOne(e => e.RomSet).WithOne(e => e.Statistics);
});
}
}
}

View File

@@ -0,0 +1,461 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using RomRepoMgr.Database;
namespace RomRepoMgr.Database.Migrations
{
[DbContext(typeof(Context))]
[Migration("20200910111423_AddStatsTable")]
partial class AddStatsTable
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "3.1.7");
modelBuilder.Entity("RomRepoMgr.Database.Models.DbDisk", b =>
{
b.Property<ulong>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<DateTime>("CreatedOn")
.HasColumnType("TEXT");
b.Property<bool>("IsInRepo")
.HasColumnType("INTEGER");
b.Property<string>("Md5")
.HasColumnType("TEXT")
.HasMaxLength(32);
b.Property<string>("OriginalFileName")
.HasColumnType("TEXT");
b.Property<string>("Sha1")
.HasColumnType("TEXT")
.HasMaxLength(40);
b.Property<ulong?>("Size")
.HasColumnType("INTEGER");
b.Property<DateTime>("UpdatedOn")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("IsInRepo");
b.HasIndex("Md5");
b.HasIndex("Sha1");
b.HasIndex("Size");
b.ToTable("Disks");
});
modelBuilder.Entity("RomRepoMgr.Database.Models.DbFile", b =>
{
b.Property<ulong>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("Crc32")
.HasColumnType("TEXT")
.HasMaxLength(8);
b.Property<DateTime>("CreatedOn")
.HasColumnType("TEXT");
b.Property<bool>("IsInRepo")
.HasColumnType("INTEGER");
b.Property<string>("Md5")
.HasColumnType("TEXT")
.HasMaxLength(32);
b.Property<string>("OriginalFileName")
.HasColumnType("TEXT");
b.Property<string>("Sha1")
.HasColumnType("TEXT")
.HasMaxLength(40);
b.Property<string>("Sha256")
.HasColumnType("TEXT")
.HasMaxLength(64);
b.Property<string>("Sha384")
.HasColumnType("TEXT")
.HasMaxLength(96);
b.Property<string>("Sha512")
.HasColumnType("TEXT")
.HasMaxLength(128);
b.Property<ulong>("Size")
.HasColumnType("INTEGER");
b.Property<DateTime>("UpdatedOn")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("Crc32");
b.HasIndex("IsInRepo");
b.HasIndex("Md5");
b.HasIndex("Sha1");
b.HasIndex("Sha256");
b.HasIndex("Sha384");
b.HasIndex("Sha512");
b.HasIndex("Size");
b.ToTable("Files");
});
modelBuilder.Entity("RomRepoMgr.Database.Models.DbMedia", b =>
{
b.Property<ulong>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<DateTime>("CreatedOn")
.HasColumnType("TEXT");
b.Property<bool>("IsInRepo")
.HasColumnType("INTEGER");
b.Property<string>("Md5")
.HasColumnType("TEXT")
.HasMaxLength(32);
b.Property<string>("OriginalFileName")
.HasColumnType("TEXT");
b.Property<string>("Sha1")
.HasColumnType("TEXT")
.HasMaxLength(40);
b.Property<string>("Sha256")
.HasColumnType("TEXT")
.HasMaxLength(64);
b.Property<ulong?>("Size")
.HasColumnType("INTEGER");
b.Property<string>("SpamSum")
.HasColumnType("TEXT");
b.Property<DateTime>("UpdatedOn")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("IsInRepo");
b.HasIndex("Md5");
b.HasIndex("Sha1");
b.HasIndex("Sha256");
b.HasIndex("Size");
b.HasIndex("SpamSum");
b.ToTable("Medias");
});
modelBuilder.Entity("RomRepoMgr.Database.Models.DiskByMachine", b =>
{
b.Property<ulong>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<ulong>("DiskId")
.HasColumnType("INTEGER");
b.Property<ulong>("MachineId")
.HasColumnType("INTEGER");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("DiskId");
b.HasIndex("MachineId");
b.HasIndex("Name");
b.ToTable("DisksByMachines");
});
modelBuilder.Entity("RomRepoMgr.Database.Models.FileByMachine", b =>
{
b.Property<ulong>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<ulong>("FileId")
.HasColumnType("INTEGER");
b.Property<DateTime?>("FileLastModification")
.HasColumnType("TEXT");
b.Property<ulong>("MachineId")
.HasColumnType("INTEGER");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("Path")
.HasColumnType("TEXT")
.HasMaxLength(4096);
b.HasKey("Id");
b.HasIndex("FileId");
b.HasIndex("MachineId");
b.HasIndex("Name");
b.ToTable("FilesByMachines");
});
modelBuilder.Entity("RomRepoMgr.Database.Models.Machine", b =>
{
b.Property<ulong>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<DateTime>("CreatedOn")
.HasColumnType("TEXT");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT");
b.Property<long>("RomSetId")
.HasColumnType("INTEGER");
b.Property<DateTime>("UpdatedOn")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("Name");
b.HasIndex("RomSetId");
b.ToTable("Machines");
});
modelBuilder.Entity("RomRepoMgr.Database.Models.MediaByMachine", b =>
{
b.Property<ulong>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<ulong>("MachineId")
.HasColumnType("INTEGER");
b.Property<ulong>("MediaId")
.HasColumnType("INTEGER");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("MachineId");
b.HasIndex("MediaId");
b.HasIndex("Name");
b.ToTable("MediasByMachines");
});
modelBuilder.Entity("RomRepoMgr.Database.Models.RomSet", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("Author")
.HasColumnType("TEXT");
b.Property<string>("Category")
.HasColumnType("TEXT");
b.Property<string>("Comment")
.HasColumnType("TEXT");
b.Property<DateTime>("CreatedOn")
.HasColumnType("TEXT");
b.Property<string>("Date")
.HasColumnType("TEXT");
b.Property<string>("Description")
.HasColumnType("TEXT");
b.Property<string>("Filename")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("Homepage")
.HasColumnType("TEXT");
b.Property<string>("Name")
.HasColumnType("TEXT");
b.Property<string>("Sha384")
.IsRequired()
.HasColumnType("TEXT")
.HasMaxLength(96);
b.Property<DateTime>("UpdatedOn")
.HasColumnType("TEXT");
b.Property<string>("Version")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("Author");
b.HasIndex("Category");
b.HasIndex("Comment");
b.HasIndex("Date");
b.HasIndex("Description");
b.HasIndex("Filename");
b.HasIndex("Homepage");
b.HasIndex("Name");
b.HasIndex("Sha384");
b.HasIndex("Version");
b.ToTable("RomSets");
});
modelBuilder.Entity("RomRepoMgr.Database.Models.RomSetStat", b =>
{
b.Property<long>("RomSetId")
.HasColumnType("INTEGER");
b.Property<long>("CompleteMachines")
.HasColumnType("INTEGER");
b.Property<long>("HaveRoms")
.HasColumnType("INTEGER");
b.Property<long>("IncompleteMachines")
.HasColumnType("INTEGER");
b.Property<long>("MissRoms")
.HasColumnType("INTEGER");
b.Property<long>("TotalMachines")
.HasColumnType("INTEGER");
b.Property<long>("TotalRoms")
.HasColumnType("INTEGER");
b.HasKey("RomSetId");
b.ToTable("RomSetStats");
});
modelBuilder.Entity("RomRepoMgr.Database.Models.DiskByMachine", b =>
{
b.HasOne("RomRepoMgr.Database.Models.DbDisk", "Disk")
.WithMany("Machines")
.HasForeignKey("DiskId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("RomRepoMgr.Database.Models.Machine", "Machine")
.WithMany("Disks")
.HasForeignKey("MachineId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("RomRepoMgr.Database.Models.FileByMachine", b =>
{
b.HasOne("RomRepoMgr.Database.Models.DbFile", "File")
.WithMany("Machines")
.HasForeignKey("FileId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("RomRepoMgr.Database.Models.Machine", "Machine")
.WithMany("Files")
.HasForeignKey("MachineId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("RomRepoMgr.Database.Models.Machine", b =>
{
b.HasOne("RomRepoMgr.Database.Models.RomSet", "RomSet")
.WithMany("Machines")
.HasForeignKey("RomSetId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("RomRepoMgr.Database.Models.MediaByMachine", b =>
{
b.HasOne("RomRepoMgr.Database.Models.Machine", "Machine")
.WithMany("Medias")
.HasForeignKey("MachineId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("RomRepoMgr.Database.Models.DbMedia", "Media")
.WithMany("Machines")
.HasForeignKey("MediaId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("RomRepoMgr.Database.Models.RomSetStat", b =>
{
b.HasOne("RomRepoMgr.Database.Models.RomSet", "RomSet")
.WithOne("Statistics")
.HasForeignKey("RomRepoMgr.Database.Models.RomSetStat", "RomSetId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
#pragma warning restore 612, 618
}
}
}

File diff suppressed because one or more lines are too long

View File

@@ -272,6 +272,27 @@ namespace RomRepoMgr.Database.Migrations
b.ToTable("RomSets");
});
modelBuilder.Entity("RomRepoMgr.Database.Models.RomSetStat", b =>
{
b.Property<long>("RomSetId").HasColumnType("INTEGER");
b.Property<long>("CompleteMachines").HasColumnType("INTEGER");
b.Property<long>("HaveRoms").HasColumnType("INTEGER");
b.Property<long>("IncompleteMachines").HasColumnType("INTEGER");
b.Property<long>("MissRoms").HasColumnType("INTEGER");
b.Property<long>("TotalMachines").HasColumnType("INTEGER");
b.Property<long>("TotalRoms").HasColumnType("INTEGER");
b.HasKey("RomSetId");
b.ToTable("RomSetStats");
});
modelBuilder.Entity("RomRepoMgr.Database.Models.DiskByMachine", b =>
{
b.HasOne("RomRepoMgr.Database.Models.DbDisk", "Disk").WithMany("Machines").HasForeignKey("DiskId").
@@ -304,6 +325,13 @@ namespace RomRepoMgr.Database.Migrations
b.HasOne("RomRepoMgr.Database.Models.DbMedia", "Media").WithMany("Machines").HasForeignKey("MediaId").
OnDelete(DeleteBehavior.Cascade).IsRequired();
});
modelBuilder.Entity("RomRepoMgr.Database.Models.RomSetStat", b =>
{
b.HasOne("RomRepoMgr.Database.Models.RomSet", "RomSet").WithOne("Statistics").
HasForeignKey("RomRepoMgr.Database.Models.RomSetStat", "RomSetId").OnDelete(DeleteBehavior.Cascade).
IsRequired();
});
#pragma warning restore 612, 618
}
}

View File

@@ -40,8 +40,9 @@ namespace RomRepoMgr.Database.Models
[Required]
public string Filename { get; set; }
[Required, StringLength(96, MinimumLength = 96)]
public string Sha384 { get; set; }
public string Category { get; set; }
public string Sha384 { get; set; }
public string Category { get; set; }
public virtual RomSetStat Statistics { get; set; }
public virtual ICollection<Machine> Machines { get; set; }
}

View File

@@ -0,0 +1,17 @@
using System.ComponentModel.DataAnnotations;
namespace RomRepoMgr.Database.Models
{
public class RomSetStat
{
public long TotalMachines { get; set; }
public long CompleteMachines { get; set; }
public long IncompleteMachines { get; set; }
public long TotalRoms { get; set; }
public long HaveRoms { get; set; }
public long MissRoms { get; set; }
public virtual RomSet RomSet { get; set; }
[Key]
public long RomSetId { get; set; }
}
}

View File

@@ -321,43 +321,23 @@ namespace RomRepoMgr.ViewModels
ThenBy(r => r.Description).ThenBy(r => r.Comment).ThenBy(r => r.Filename).
Select(r => new RomSetModel
{
Id = r.Id,
Author = r.Author,
Comment = r.Comment,
Date = r.Date,
Description = r.Description,
Filename = r.Filename,
Homepage = r.Homepage,
Name = r.Name,
Sha384 = r.Sha384,
Version = r.Version,
TotalMachines = r.Machines.Count,
CompleteMachines =
r.Machines.Count(m => m.Files.Count > 0 && m.Disks.Count == 0 &&
m.Files.All(f => f.File.IsInRepo)) +
r.Machines.Count(m => m.Disks.Count > 0 && m.Files.Count == 0 &&
m.Disks.All(f => f.Disk.IsInRepo)) +
r.Machines.Count(m => m.Files.Count > 0 && m.Disks.Count > 0 &&
m.Files.All(f => f.File.IsInRepo) &&
m.Disks.All(f => f.Disk.IsInRepo)),
IncompleteMachines =
r.Machines.Count(m => m.Files.Count > 0 && m.Disks.Count == 0 &&
m.Files.Any(f => !f.File.IsInRepo)) +
r.Machines.Count(m => m.Disks.Count > 0 && m.Files.Count == 0 &&
m.Disks.Any(f => !f.Disk.IsInRepo)) +
r.Machines.Count(m => m.Files.Count > 0 && m.Disks.Count > 0 &&
(m.Files.Any(f => !f.File.IsInRepo) ||
m.Disks.Any(f => !f.Disk.IsInRepo))),
TotalRoms = r.Machines.Sum(m => m.Files.Count) +
r.Machines.Sum(m => m.Disks.Count) +
r.Machines.Sum(m => m.Medias.Count),
HaveRoms = r.Machines.Sum(m => m.Files.Count(f => f.File.IsInRepo)) +
r.Machines.Sum(m => m.Disks.Count(f => f.Disk.IsInRepo)) +
r.Machines.Sum(m => m.Medias.Count(f => f.Media.IsInRepo)),
MissRoms = r.Machines.Sum(m => m.Files.Count(f => !f.File.IsInRepo)) +
r.Machines.Sum(m => m.Disks.Count(f => !f.Disk.IsInRepo)) +
r.Machines.Sum(m => m.Medias.Count(f => !f.Media.IsInRepo)),
Category = r.Category
Id = r.Id,
Author = r.Author,
Comment = r.Comment,
Date = r.Date,
Description = r.Description,
Filename = r.Filename,
Homepage = r.Homepage,
Name = r.Name,
Sha384 = r.Sha384,
Version = r.Version,
TotalMachines = r.Statistics.TotalMachines,
CompleteMachines = r.Statistics.CompleteMachines,
IncompleteMachines = r.Statistics.IncompleteMachines,
TotalRoms = r.Statistics.TotalRoms,
HaveRoms = r.Statistics.HaveRoms,
MissRoms = r.Statistics.MissRoms,
Category = r.Category
}).ToList()
});