foreign keys for table PairData + DragonId column + DB schema improvements (#30)

* DB schema improvements

- add column DragonId to table PairData
- add foreign keys for table PairData
- remove unused column InventoryId from Vikings table
- simplifying relations viking -> selected dragon
  - remove SelectedViking and SelectedVikingId from Dragon
  - remove column SelectedVikingId from Dragons table
- cleanup and arrangement code in DBContext.cs

* support for dragons PairData in KeyValueService

and in "pairs" API endpoints
This commit is contained in:
rpaciorek 2023-08-31 18:46:03 +00:00 committed by GitHub
parent 7bee6c620a
commit 81e5718e05
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 113 additions and 69 deletions

View File

@ -120,7 +120,7 @@ public class ContentController : Controller {
return null; return null;
// Get the pair // Get the pair
Model.PairData? pair = keyValueService.GetPairData(session.UserId, session.VikingId, pairId); Model.PairData? pair = keyValueService.GetPairData(session.User, session.Viking, null, pairId);
return keyValueService.ModelToSchema(pair); return keyValueService.ModelToSchema(pair);
} }
@ -136,7 +136,7 @@ public class ContentController : Controller {
if (session is null) if (session is null)
return Ok(false); return Ok(false);
bool result = keyValueService.SetPairData(session.UserId, session.VikingId, pairId, schemaData); bool result = keyValueService.SetPairData(session.User, session.Viking, null, pairId, schemaData);
return Ok(result); return Ok(result);
} }
@ -149,7 +149,7 @@ public class ContentController : Controller {
if (session is null) if (session is null)
return null; return null;
Model.PairData? pair = keyValueService.GetPairData(userId, null, pairId); Model.PairData? pair = keyValueService.GetPairData(session.User, session.Viking, userId, pairId);
return keyValueService.ModelToSchema(pair); return keyValueService.ModelToSchema(pair);
} }
@ -165,7 +165,7 @@ public class ContentController : Controller {
if (session is null || string.IsNullOrEmpty(userId)) if (session is null || string.IsNullOrEmpty(userId))
return Ok(false); return Ok(false);
bool result = keyValueService.SetPairData(userId, null, pairId, schemaData); bool result = keyValueService.SetPairData(session.User, session.Viking, userId, pairId, schemaData);
return Ok(result); return Ok(result);
} }
@ -1231,7 +1231,7 @@ public class ContentController : Controller {
RaisedPetData data = XmlUtil.DeserializeXml<RaisedPetData>(dragon.RaisedPetData); RaisedPetData data = XmlUtil.DeserializeXml<RaisedPetData>(dragon.RaisedPetData);
data.RaisedPetID = dragon.Id; data.RaisedPetID = dragon.Id;
data.EntityID = Guid.Parse(dragon.EntityId); data.EntityID = Guid.Parse(dragon.EntityId);
data.IsSelected = dragon.SelectedViking is not null; data.IsSelected = (dragon.Viking.SelectedDragonId == dragon.Id);
return data; return data;
} }

View File

@ -26,6 +26,7 @@ public class DBContext : DbContext {
=> optionsBuilder.UseSqlite($"Data Source={DbPath}").UseLazyLoadingProxies(); => optionsBuilder.UseSqlite($"Data Source={DbPath}").UseLazyLoadingProxies();
protected override void OnModelCreating(ModelBuilder builder) { protected override void OnModelCreating(ModelBuilder builder) {
// Sessions
builder.Entity<Session>().HasOne(s => s.User) builder.Entity<Session>().HasOne(s => s.User)
.WithMany(e => e.Sessions) .WithMany(e => e.Sessions)
.HasForeignKey(e => e.UserId) .HasForeignKey(e => e.UserId)
@ -36,10 +37,25 @@ public class DBContext : DbContext {
.HasForeignKey(e => e.VikingId) .HasForeignKey(e => e.VikingId)
.OnDelete(DeleteBehavior.Cascade); .OnDelete(DeleteBehavior.Cascade);
// Users
builder.Entity<User>().HasMany(u => u.Sessions) builder.Entity<User>().HasMany(u => u.Sessions)
.WithOne(e => e.User); .WithOne(e => e.User);
builder.Entity<Viking>().HasMany(u => u.Sessions) builder.Entity<User>().HasMany(u => u.PairData)
.WithOne(e => e.User);
builder.Entity<User>().HasMany(u => u.Vikings)
.WithOne(e => e.User);
// Vikings
builder.Entity<Viking>().HasOne(v => v.User)
.WithMany(e => e.Vikings)
.HasForeignKey(e => e.UserId);
builder.Entity<Viking>().HasMany(v => v.Dragons)
.WithOne(e => e.Viking);
builder.Entity<Viking>().HasMany(v => v.Sessions)
.WithOne(e => e.Viking); .WithOne(e => e.Viking);
builder.Entity<Viking>().HasMany(v => v.MissionStates) builder.Entity<Viking>().HasMany(v => v.MissionStates)
@ -51,62 +67,53 @@ public class DBContext : DbContext {
builder.Entity<Viking>().HasMany(v => v.AchievementPoints) builder.Entity<Viking>().HasMany(v => v.AchievementPoints)
.WithOne(e => e.Viking); .WithOne(e => e.Viking);
builder.Entity<Viking>().HasOne(s => s.User) builder.Entity<Viking>().HasMany(v => v.PairData)
.WithMany(e => e.Vikings) .WithOne(e => e.Viking);
.HasForeignKey(e => e.UserId);
builder.Entity<Viking>().HasOne(v => v.Inventory) builder.Entity<Viking>().HasOne(v => v.Inventory)
.WithOne(e => e.Viking) .WithOne(e => e.Viking);
.HasForeignKey<Viking>(e => e.InventoryId);
builder.Entity<User>().HasMany(u => u.Vikings) builder.Entity<Viking>().HasMany(v => v.Images)
.WithOne(e => e.User); .WithOne(e => e.Viking);
builder.Entity<Dragon>().HasOne(s => s.Viking) builder.Entity<Viking>().HasOne(v => v.SelectedDragon)
.WithOne()
.HasForeignKey<Viking>(e => e.SelectedDragonId);
// Dragons
builder.Entity<Dragon>().HasOne(d => d.Viking)
.WithMany(e => e.Dragons) .WithMany(e => e.Dragons)
.HasForeignKey(e => e.VikingId); .HasForeignKey(e => e.VikingId);
builder.Entity<Viking>().HasMany(u => u.Dragons) builder.Entity<Dragon>().HasMany(d => d.PairData)
.WithOne(e => e.Viking); .WithOne(e => e.Dragon);
builder.Entity<Viking>().HasOne(s => s.SelectedDragon)
.WithOne(e => e.SelectedViking)
.HasForeignKey<Dragon>(e => e.SelectedVikingId);
builder.Entity<Dragon>().HasOne(s => s.SelectedViking)
.WithOne(e => e.SelectedDragon)
.HasForeignKey<Viking>(e => e.SelectedDragonId);
builder.Entity<Image>().HasOne(s => s.Viking)
.WithMany(e => e.Images)
.HasForeignKey(e => e.VikingId);
builder.Entity<Viking>().HasMany(u => u.Images)
.WithOne(e => e.Viking);
builder.Entity<Viking>().HasOne(v => v.Inventory)
.WithOne(e => e.Viking);
builder.Entity<PairData>()
.HasKey(e => e.Id);
// PairData & Pair
builder.Entity<PairData>().HasMany(p => p.Pairs) builder.Entity<PairData>().HasMany(p => p.Pairs)
.WithOne(e => e.PairData); .WithOne(e => e.PairData);
builder.Entity<PairData>().HasOne(p => p.Viking)
.WithMany(e => e.PairData)
.HasForeignKey(e => e.VikingId)
.OnDelete(DeleteBehavior.Cascade);
builder.Entity<PairData>().HasOne(p => p.User)
.WithMany(e => e.PairData)
.HasForeignKey(e => e.UserId)
.OnDelete(DeleteBehavior.Cascade);
builder.Entity<PairData>().HasOne(p => p.Dragon)
.WithMany(e => e.PairData)
.HasForeignKey(e => e.DragonId)
.OnDelete(DeleteBehavior.Cascade);
builder.Entity<Pair>() builder.Entity<Pair>()
.HasOne(p => p.PairData) .HasOne(p => p.PairData)
.WithMany(pd => pd.Pairs) .WithMany(pd => pd.Pairs)
.HasForeignKey(p => p.MasterId) .HasForeignKey(p => p.MasterId)
.HasPrincipalKey(e => e.Id); .HasPrincipalKey(e => e.Id);
builder.Entity<TaskStatus>().HasKey(e => new { e.Id, e.VikingId, e.MissionId }); // Inventory & InventoryItem
builder.Entity<TaskStatus>()
.HasOne(t => t.Viking)
.WithMany();
builder.Entity<Inventory>().HasKey(e => e.Id);
builder.Entity<Inventory>() builder.Entity<Inventory>()
.HasOne(i => i.Viking) .HasOne(i => i.Viking)
.WithOne(e => e.Inventory) .WithOne(e => e.Inventory)
@ -121,10 +128,7 @@ public class DBContext : DbContext {
.WithMany(e => e.InventoryItems) .WithMany(e => e.InventoryItems)
.HasForeignKey(e => e.InventoryId); .HasForeignKey(e => e.InventoryId);
builder.Entity<MissionState>().HasOne(m => m.Viking) // Room & RoomItem
.WithMany(e => e.MissionStates)
.HasForeignKey(e => e.VikingId);
builder.Entity<Room>().HasOne(r => r.Viking) builder.Entity<Room>().HasOne(r => r.Viking)
.WithMany(e => e.Rooms) .WithMany(e => e.Rooms)
.HasForeignKey(e => e.VikingId); .HasForeignKey(e => e.VikingId);
@ -136,6 +140,21 @@ public class DBContext : DbContext {
.WithMany(r => r.Items) .WithMany(r => r.Items)
.HasForeignKey(e => e.RoomId); .HasForeignKey(e => e.RoomId);
// Others ..
builder.Entity<Image>().HasOne(s => s.Viking)
.WithMany(e => e.Images)
.HasForeignKey(e => e.VikingId);
builder.Entity<TaskStatus>().HasKey(e => new { e.Id, e.VikingId, e.MissionId });
builder.Entity<TaskStatus>()
.HasOne(t => t.Viking)
.WithMany();
builder.Entity<MissionState>().HasOne(m => m.Viking)
.WithMany(e => e.MissionStates)
.HasForeignKey(e => e.VikingId);
builder.Entity<AchievementPoints>().HasKey(e => new { e.VikingId, e.Type }); builder.Entity<AchievementPoints>().HasKey(e => new { e.VikingId, e.Type });
builder.Entity<AchievementPoints>() builder.Entity<AchievementPoints>()

View File

@ -14,12 +14,10 @@ public class Dragon {
[Required] [Required]
public string VikingId { get; set; } = null!; public string VikingId { get; set; } = null!;
public string? SelectedVikingId { get; set; }
public string? RaisedPetData { get; set; } public string? RaisedPetData { get; set; }
public int? PetXP { get; set; } public int? PetXP { get; set; }
public virtual Viking Viking { get; set; } = null!; public virtual Viking Viking { get; set; } = null!;
public virtual Viking SelectedViking { get; set; } = null!; public virtual ICollection<PairData> PairData { get; set; } = null!;
} }

View File

@ -17,5 +17,13 @@ public class PairData {
public string? VikingId { get; set; } public string? VikingId { get; set; }
public int? DragonId { get; set; }
public virtual ICollection<Pair> Pairs { get; set; } public virtual ICollection<Pair> Pairs { get; set; }
public virtual User? User { get; set; }
public virtual Viking? Viking { get; set; }
public virtual Dragon? Dragon { get; set; }
} }

View File

@ -15,6 +15,6 @@ public class User {
public string Password { get; set; } = null!; public string Password { get; set; } = null!;
public virtual ICollection<Session> Sessions { get; set; } = null!; public virtual ICollection<Session> Sessions { get; set; } = null!;
public virtual ICollection<Viking> Vikings { get; set; } = null!; public virtual ICollection<Viking> Vikings { get; set; } = null!;
public virtual ICollection<PairData> PairData { get; set; } = null!;
} }

View File

@ -22,9 +22,7 @@ public class Viking {
public virtual ICollection<MissionState> MissionStates { get; set; } = null!; public virtual ICollection<MissionState> MissionStates { get; set; } = null!;
public virtual ICollection<Room> Rooms { get; set; } = null!; public virtual ICollection<Room> Rooms { get; set; } = null!;
public virtual ICollection<AchievementPoints> AchievementPoints { get; set; } = null!; public virtual ICollection<AchievementPoints> AchievementPoints { get; set; } = null!;
public virtual Dragon? SelectedDragon { get; set; } public virtual ICollection<PairData> PairData { get; set; } = null!;
public int InventoryId { get; set; }
public virtual Inventory Inventory { get; set; } = null!; public virtual Inventory Inventory { get; set; } = null!;
public virtual Dragon? SelectedDragon { get; set; }
} }

View File

@ -10,27 +10,24 @@ public class KeyValueService {
this.ctx = ctx; this.ctx = ctx;
} }
public Model.PairData? GetPairData(string? UserId, string? VikingId, int pairId) { public Model.PairData? GetPairData(User? user, Viking? viking, string? userId, int pairId) {
Model.PairData? pair = null; Dragon? dragon = null;
if (VikingId != null) return CheckOwnerAndGetPairData(ref user, ref viking, ref dragon, userId, pairId);
pair = ctx.PairData.FirstOrDefault(e => e.PairId == pairId && e.VikingId == VikingId);
else if (UserId != null)
pair = ctx.PairData.FirstOrDefault(e => e.PairId == pairId && e.UserId == UserId);
return pair;
} }
public bool SetPairData(string? UserId, string? VikingId, int pairId, Schema.PairData schemaData) { public bool SetPairData(User? user, Viking? viking, string? userId, int pairId, Schema.PairData schemaData) {
// Get the pair // Get the pair
Model.PairData? pair = GetPairData(UserId, VikingId, pairId); Dragon? dragon = null;
Model.PairData? pair = CheckOwnerAndGetPairData(ref user, ref viking, ref dragon, userId, pairId);
// Create the pair if it doesn't exist // Create the pair if it doesn't exist
bool exists = true; bool exists = true;
if (pair is null) { if (pair is null) {
pair = new Model.PairData { pair = new Model.PairData {
PairId = pairId, PairId = pairId,
UserId = UserId, UserId = user?.Id,
VikingId = VikingId, VikingId = viking?.Id,
DragonId = dragon?.Id,
Pairs = new List<Model.Pair>() Pairs = new List<Model.Pair>()
}; };
exists = false; exists = false;
@ -77,4 +74,28 @@ public class KeyValueService {
return new Schema.PairData { Pairs = pairs.ToArray() }; return new Schema.PairData { Pairs = pairs.ToArray() };
} }
private Model.PairData? CheckOwnerAndGetPairData(ref User? user, ref Viking? viking, ref Dragon dragon, string? userId, int pairId) {
if (userId != null) {
// find dragon
dragon = viking?.Dragons.FirstOrDefault(e => e.EntityId == userId);
// if not dragon then try viking -> check ID
if (dragon != null || viking?.Id != userId) viking = null;
// if not dragon nor viking then try user -> check ID
if (viking != null || user?.Id != userId) user = null;
}
// NOTE: only one of (dragon, viking, user) can be not null here
Model.PairData? pair = null;
if (viking != null)
pair = viking.PairData.FirstOrDefault(e => e.PairId == pairId);
else if (user != null)
pair = user.PairData.FirstOrDefault(e => e.PairId == pairId);
else if (dragon != null)
pair = dragon.PairData.FirstOrDefault(e => e.PairId == pairId);
return pair;
}
} }