.Net 3.1 DataSeeding order of operation problem - mysql

I'm trying to seed a database with about 1000 users and agents and about 5000 posts.
I have added the users and agents but when I try to add the posts the migration gets created normally but the update-database command return an error.
I tried adding a user manually, created a post with the users id and added a migration just for the post and it worked.
I think that this is a order of operations problem. I'm thinking that when the post is being inserted to the database it cannot find the user it is looking for because the user is not in the database yet.
Any help is greatly appreciated.
Thank you for your time in advance <3.
The error reads:
Build started...
Build succeeded.
fail: Microsoft.EntityFrameworkCore.Database.Command[20102]
Failed executing DbCommand (25ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
IF EXISTS (SELECT * FROM [sys].[identity_columns] WHERE [name] IN (N'Id', N'Baths', N'Beds', N'BuildingType', N'CategoryId', N'City', N'County', N'CreatedAt', N'Description', N'HouseNumber', N'IsActive', N'IsDeleted', N'IsPrioritize', N'IsPublished', N'Latitude', N'Longitute', N'OwnerId', N'PostalCode', N'Price', N'Size', N'State', N'Street', N'StreetNumber', N'Title') AND [object_id] = OBJECT_ID(N'[Post]'))
SET IDENTITY_INSERT [Post] ON;
INSERT INTO [Post] ([Id], [Baths], [Beds], [BuildingType], [CategoryId], [City], [County], [CreatedAt], [Description], [HouseNumber], [IsActive], [IsDeleted], [IsPrioritize], [IsPublished], [Latitude], [Longitute], [OwnerId], [PostalCode], [Price], [Size], [State], [Street], [StreetNumber], [Title])
VALUES (1, 3, 5, 1, 1, N'New York', N'New Work', '2022-08-04T10:58:44.5986172+02:00', N'We are selling a house blla blla', 15, CAST(0 AS bit), CAST(0 AS bit), CAST(0 AS bit), CAST(1 AS bit), 30.899999999999999E0, 15.5E0, N'00e0ad26-5df2-45a8-a929-dde8f9c429c3', N'15863', 150000.0E0, 150, N'New York', N'83rd Street', 186, N'Selling House');
IF EXISTS (SELECT * FROM [sys].[identity_columns] WHERE [name] IN (N'Id', N'Baths', N'Beds', N'BuildingType', N'CategoryId', N'City', N'County', N'CreatedAt', N'Description', N'HouseNumber', N'IsActive', N'IsDeleted', N'IsPrioritize', N'IsPublished', N'Latitude', N'Longitute', N'OwnerId', N'PostalCode', N'Price', N'Size', N'State', N'Street', N'StreetNumber', N'Title') AND [object_id] = OBJECT_ID(N'[Post]'))
SET IDENTITY_INSERT [Post] OFF;
Failed executing DbCommand (25ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
IF EXISTS (SELECT * FROM [sys].[identity_columns] WHERE [name] IN (N'Id', N'Baths', N'Beds', N'BuildingType', N'CategoryId', N'City', N'County', N'CreatedAt', N'Description', N'HouseNumber', N'IsActive', N'IsDeleted', N'IsPrioritize', N'IsPublished', N'Latitude', N'Longitute', N'OwnerId', N'PostalCode', N'Price', N'Size', N'State', N'Street', N'StreetNumber', N'Title') AND [object_id] = OBJECT_ID(N'[Post]'))
SET IDENTITY_INSERT [Post] ON;
INSERT INTO [Post] ([Id], [Baths], [Beds], [BuildingType], [CategoryId], [City], [County], [CreatedAt], [Description], [HouseNumber], [IsActive], [IsDeleted], [IsPrioritize], [IsPublished], [Latitude], [Longitute], [OwnerId], [PostalCode], [Price], [Size], [State], [Street], [StreetNumber], [Title])
VALUES (1, 3, 5, 1, 1, N'New York', N'New Work', '2022-08-04T10:58:44.5986172+02:00', N'We are selling a house blla blla', 15, CAST(0 AS bit), CAST(0 AS bit), CAST(0 AS bit), CAST(1 AS bit), 30.899999999999999E0, 15.5E0, N'00e0ad26-5df2-45a8-a929-dde8f9c429c3', N'15863', 150000.0E0, 150, N'New York', N'83rd Street', 186, N'Selling House');
IF EXISTS (SELECT * FROM [sys].[identity_columns] WHERE [name] IN (N'Id', N'Baths', N'Beds', N'BuildingType', N'CategoryId', N'City', N'County', N'CreatedAt', N'Description', N'HouseNumber', N'IsActive', N'IsDeleted', N'IsPrioritize', N'IsPublished', N'Latitude', N'Longitute', N'OwnerId', N'PostalCode', N'Price', N'Size', N'State', N'Street', N'StreetNumber', N'Title') AND [object_id] = OBJECT_ID(N'[Post]'))
SET IDENTITY_INSERT [Post] OFF;
Microsoft.Data.SqlClient.SqlException (0x80131904): The INSERT statement conflicted with the FOREIGN KEY constraint "FK_Post_AspNetUsers_OwnerId". The conflict occurred in database "Team3UberMain", table "dbo.AspNetUsers", column 'Id'.
The statement has been terminated.
at Microsoft.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at Microsoft.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at Microsoft.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
at Microsoft.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
at Microsoft.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName, Boolean isAsync, Int32 timeout, Boolean asyncWrite)
at Microsoft.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, Boolean sendToPipe, Int32 timeout, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry, String methodName)
at Microsoft.Data.SqlClient.SqlCommand.ExecuteNonQuery()
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteNonQuery(RelationalCommandParameterObject parameterObject)
at Microsoft.EntityFrameworkCore.Migrations.MigrationCommand.ExecuteNonQuery(IRelationalConnection connection, IReadOnlyDictionary`2 parameterValues)
at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationCommandExecutor.ExecuteNonQuery(IEnumerable`1 migrationCommands, IRelationalConnection connection)
at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.Migrate(String targetMigration)
at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.UpdateDatabase(String targetMigration, String contextType)
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.UpdateDatabaseImpl(String targetMigration, String contextType)
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.UpdateDatabase.<>c__DisplayClass0_0.<.ctor>b__0()
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
ClientConnectionId:4e393a1b-a11d-4a8d-a2bb-646dd3c14e58
Error Number:547,State:0,Class:16
The INSERT statement conflicted with the FOREIGN KEY constraint "FK_Post_AspNetUsers_OwnerId". The conflict occurred in database "Team3UberMain", table "dbo.AspNetUsers", column 'Id'.
The statement has been terminated.
PM> Add-Migration Init
Build started...
Build succeeded.
To undo this action, use Remove-Migration.
This is the class responsible for seeding the data (focus on AddUsers and AddPosts) :
public static class AddData
{
private static List<string> NamesList {
get {
return new List<string>("Liam,Noah,Oliver,Elijah,James,...,William,Benjamin".Split(","));
}
}
private static List<string> GetSurnamesList(int i = 0) {
string[] surnames = "Smith,Johnson,Williams,Brown,...,Tang,Archer".Split(",");
if (i > 0) Rotate(ref surnames, i);
return new List<string>(surnames);
}
private static int NrOfUsers = 0;
public static void AddUsers(ModelBuilder mb){
List<string> Names = NamesList;
List<string> Surnames = GetSurnamesList();
List<User> UsersList = new List<User>();
for (int i = 0; i < Names.Count; i++) {
string name = Names[i];
string surname = Surnames[i];
string phoneNumber = "0"+(44000000+i+NrOfUsers);
DateTime dateTime = DateTime.Now;
int userId = i+NrOfUsers;
string emailDomain = i % 3 == 0 ? "#gmail.com" : (i % 3 == 1 ? "#hotmail.com" : "#outlook.com");
string email = name + surname + emailDomain;
string password = name +surname +"123.";
string hash = HashPassword(password);
User u = new User
{
Email = email,
NormalizedEmail = email.ToUpper(),
EmailConfirmed = true,
UserName = email,
NormalizedUserName = email.ToUpper(),
UserId = userId,
FirstName = name,
LastName = surname,
Password = password,
PasswordHash = hash,
ConfirmPassword = password,
PhoneNumber = phoneNumber,
DateOfBirth = dateTime,
LockoutEnabled = true,
IsDeleted = false,
};
UsersList.Add(u);
}
mb.Entity<User>().HasData(UsersList);
NrOfUsers += Names.Count;
}
public static void AddAgents(ModelBuilder mb)
{
List<string> Names = NamesList;
List<string> Surnames = GetSurnamesList(1);
List<Agent> AgentsList = new List<Agent>();
for (int i = 0; i < Names.Count; i++)
{
string name = Names[i];
string surname = Surnames[i];
string phoneNumber = "0" + (44555000 + i+ NrOfUsers);
DateTime dateTime = DateTime.Now;
int userId = i+NrOfUsers;
string emailDomain = i % 3 == 0 ? "#gmail.com" : (i % 3 == 1 ? "#hotmail.com" : "#outlook.com");
string email = name + surname + emailDomain;
string password = name + surname + "123.";
string hash = HashPassword(password);
Agent a = new Agent
{
Email = email,
NormalizedEmail = email.ToUpper(),
EmailConfirmed = true,
UserName = email,
NormalizedUserName = email.ToUpper(),
UserId = userId,
FirstName = name,
LastName = surname,
Password = password,
PasswordHash = hash,
ConfirmPassword = password,
PhoneNumber = phoneNumber,
DateOfBirth = dateTime,
LockoutEnabled = true,
IsDeleted = false,
AgentId = 100000 + i + NrOfUsers
};
AgentsList.Add(a);
}
mb.Entity<Agent>().HasData(AgentsList);
NrOfUsers += Names.Count;
}
public static void AddCategorys(ModelBuilder mb) {
mb.Entity<Category>().HasData(
new Category() { Id = 1, CategoryName = "Land", },
new Category() { Id = 2, CategoryName = "Apartment" },
new Category() { Id = 3, CategoryName = "House" },
new Category() { Id = 4, CategoryName = "Farm" },
new Category() { Id = 5, CategoryName = "Barn" },
new Category() { Id = 6, CategoryName = "Flat" },
new Category() { Id = 7, CategoryName = "Penthouse" }
) ;
}
public static void AddPosts(ModelBuilder mb)
{
mb.Entity<Post>().HasData(
new Post
{
Id = 1,
Title = "Selling House",
Price = 150000,
State = "New York",
City = "New York",
PostalCode = "15863",
Street = "83rd Street",
HouseNumber = 15,
StreetNumber = 186,
County = "New Work",
CategoryId = 1,
// // todo : mi ndrreq owner id se osht string i gat
OwnerId = "00e0ad26-5df2-45a8-a929-dde8f9c429c3",
Description = "We are selling a house blla blla",
Longitute = 15.5,
Latitude = 30.9,
BuildingType = 1,
Size = 150,
Beds = 5,
Baths = 3,
CreatedAt = DateTime.Now,
IsPrioritize = false,
// TODO: add images and sponsored
IsPublished = true
}
);
}
private static void Rotate<T>(ref T[] array, int shiftCount)
{
if (shiftCount == 0) return;
T[] backupArray = new T[array.Length];
for (int index = 0; index < array.Length; index++)
{
backupArray[(index + array.Length + shiftCount % array.Length) % array.Length] = array[index];
}
array = backupArray;
}
private static string HashPassword(string password)
{
byte[] salt;
byte[] buffer2;
if (password == null)
{
throw new ArgumentNullException("password");
}
using (Rfc2898DeriveBytes bytes = new Rfc2898DeriveBytes(password, 0x10, 0x3e8))
{
salt = bytes.Salt;
buffer2 = bytes.GetBytes(0x20);
}
byte[] dst = new byte[0x31];
Buffer.BlockCopy(salt, 0, dst, 1, 0x10);
Buffer.BlockCopy(buffer2, 0, dst, 0x11, 0x20);
return Convert.ToBase64String(dst);
}
}
This are the user and post models:
public class User : IdentityUser
{
public int UserId { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
[Required]
public string Password { get; set; }
[Required]
public string ConfirmPassword { get; set; }
[Required]
public DateTime DateOfBirth { get; set; }
[Required]
public bool IsDeleted { get; set; }
[Required]
public bool IsActive { get; set; }
public List<Post> Posts { get; set; }
//public Guid ResetToken { get; set; }
}
public class Post : BaseAttributes
{
[Key]
public int Id { get; set; }
[Required]
public string Title { get; set; }
public double Price { get; set; }
[Required]
public string State { get; set; }
[Required]
public string City { get; set; }
public string PostalCode { get; set; }
public string Street { get; set; }
public int HouseNumber { get; set; }
public int StreetNumber { get; set; }
public string County { get; set; }
public int? CategoryId { get; set; }
[ForeignKey("CategoryId")]
public Category Category { get; set; }
public string OwnerId { get; set; }
[ForeignKey("OwnerId")]
public User Owner { get; set; }
[Required]
public string Description { get; set; }
[Required]
public double Longitute { get; set; }
[Required]
public double Latitude { get; set; }
[Required]
public int BuildingType { get; set; }
[Required]
public int Size { get; set; }
[Required]
public int Beds { get; set; }
[Required]
public int Baths { get; set; }
[Required]
public DateTime CreatedAt { get; set; } = DateTime.Now;
public bool IsPrioritize { get; set; }
public List<Image> Images { get; set; }
public List<Sponsored> Sponsored { get; set; }
public bool IsPublished { get; set; } = false;
public virtual ICollection<Taken_By_Relation> Taken_by_list { get; set; }
}
This is the ApplicationDbContext:
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
{
}
public DbSet<User> User { get; set; }
public DbSet<Agent> Agent { get; set; }
public DbSet<SimpleUser> SimpleUser { get; set; }
public DbSet<Post> Post { get; set; }
public DbSet<Image> Image { get; set; }
public DbSet<Category> Category { get; set; }
public DbSet<Agent_Post_CounterOffer> Agent_Post_CounterOffer { get; set; }
public DbSet<CounterOffer> CounterOffer { get; set; }
public DbSet<FeedBack> FeedBack { get; set; }
public DbSet<Salary> Salary { get; set; }
public DbSet<Taken_By_Relation> Taken_By_Relation { get; set; }
public DbSet<Given_By_Relation> Given_By_Relation { get; set; }
public DbSet<Sponsored> Sponsored{ get; set; }
//public DbSet<Invite> Invite{ get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder) {
AddData.AddUsers(modelBuilder);
AddData.AddAgents(modelBuilder);
AddData.AddCategorys(modelBuilder);
AddData.AddPosts(modelBuilder);
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Agent_Post_CounterOffer>().HasNoKey();
modelBuilder.Entity<Given_By_Relation>().HasNoKey();
modelBuilder.Entity<ChangePasswordViewModel>().HasNoKey();
modelBuilder.Entity<Salary>().HasNoKey();
//modelBuilder.Entity<Agent_Post_CounterOffer>().HasKey(ap => new { ap.AgentId, ap.PostId, ap.CounterOfferId });
//modelBuilder.Entity<Given_By_Relation>().HasKey(ap => new { ap.Given_By, ap.JobId, ap.PostId });
//modelBuilder.Entity<Taken_By_Relation>().HasKey(ap => new { ap.Taken_By, ap.JobId, ap.PostId });
}
}

Related

How to restructure an Object in C# using LINQ?

I have a data set as follows:
[
{
"Id": 1,
"Country": "Uruguay",
"Name": "Foo",
"Status": "Completed",
},
{
"Id": 2,
"Country": "Uruguay",
"Name": "Foo",
"Status": "Completed",
},
{
"Id": 3,
"Country": "Germany",
"Name": "Foo",
"Status": "Completed",
},
]
I want to transform and sort it by Country so that it looks as follows:
[
{
"Country": "Uruguay",
"Details": [
{
"Id": 1,
"Name": "Foo",
"Status": "Completed",
},
{
"Id": 2,
"Name": "Foo",
"Status": "Completed",
},
],
},
{
"Country": "Germany",
"Details": [
{
"Id": 3,
"Name": "Foo",
"Status": "Completed",
},
],
},
],
These are the classes in C#:
public class Countries {
public int Id { get; set; }
public string Country { get; set; }
public string Name { get; set; }
public string Status { get; set; }
}
public class Details {
public int Id { get; set; }
public string Name { get; set; }
public string Status { get; set; }
}
public class CountryList {
public string Country { get; set; }
public List<Details> Details { get; set; }
}
Some of what I have tried looks as followed:
var foo = countries
.GroupBy(x => new Details { Id = x.Id, Name = x.Name, Status = x.Status })
.Select( y => new CountryList
{
// Country = y.Key.
}
var foo = countries
.GroupBy(x => x.Country)
.Select( y => new CountryList
{
// Country = y.Key.
Details = y.GroupBy(a => new Details
{
Id = a.Id,
Name = a.Name,
Status = a.Status
}).ToList()
}
I am having trouble working out how to use LINQ to solve this. I have done a handful of GroupBy operations in the past, but I wasn't able to work this one out. How do I transform my dataset into the desired result?
You do not need second GroupBy
var foo = countries
.GroupBy(x => x.Country)
.Select(y => new CountryList
{
Country = y.Key,
Details = y.Select(a => new Details
{
Id = a.Id,
Name = a.Name,
Status = a.Status
}).ToList()
};
You can take advantage of the .GroupBy() overload that lets you define a resultSelector to create your CountryLists and populate their Details:
var countries = new List<Countries>
{
new() { Id = 1, Country = "Uruguay", Name = "Foo", Status = "Completed" },
new() { Id = 2, Country = "Uruguay", Name = "Foo", Status = "Completed" },
new() { Id = 3, Country = "Germany", Name = "Foo", Status = "Completed" },
};
List<CountryList> countryList = countries
.GroupBy(
c => c.Country,
( country, matches ) => new CountryList()
{
Country = country,
Details = matches.Select(match => new Details
{
Id = match.Id,
Name = match.Name,
Status = match.Status
}).ToList()
})
.ToList();
, ( country, matches ) => new CountryList() { ... } being the resultSelector.
Example fiddle here.
try this
var orig = JsonConvert.DeserializeObject<List<Countries>>(json);
List<CountryList> countries = orig.GroupBy(o => o.Country)
.Select(x => new CountryList {
Country = x.Key,
Details = x.Select(o => new Details {Id=o.Id,Name=o.Name,Status=o.Status} ).ToList()
}).ToList();

Why is my data getting associated with wrong column in mysql db?

I have two tables connected with a many to many relationship using a composite key:
Table1
#Entity
#Table(name = "user")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "user_name")
private String userName;
#Column(name = "first_name")
private String firstName;
#Column(name = "last_name")
private String lastName;
private String password;
private String authorization;
#OneToMany(
mappedBy = "user",
cascade = CascadeType.ALL,
orphanRemoval = true
)
#JsonManagedReference
private List<UserProduct> userProducts = new ArrayList<>();
#OneToMany(
mappedBy = "user",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<Orders> orders = new ArrayList<>();
Table2
#Entity
#Table(name = "product")
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
private int price;
private double mass;
private double alcohol;
private String picture;
private int amount;
#OneToMany(
mappedBy = "user",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<UserProduct> userProducts = new ArrayList<>();
#OneToMany(
mappedBy = "orders",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<OrderProduct> orderProducts = new ArrayList<>();
Table with composite key
#Entity
#Table(name = "user_product")
public class UserProduct {
#EmbeddedId
private UserProductId id;
#ManyToOne(fetch = FetchType.LAZY)
#MapsId("userId")
#JsonBackReference
private User user;
#ManyToOne(fetch = FetchType.LAZY)
#MapsId("productId")
private Product product;
#Column(name = "amount_of_new_products")
private int amountOfNewProducts;
When I make a REST call to UserProduct table so i can update the product value using this payload:
{
"user": 4,
"product": 2,
"amountOfNewProducts": 32
}
it writes the information depending on what is the user id and not the product id. For this payload it would write in like this:
{
"id": 3,
"name": "Grimbergen Blanche",
"price": 132,
"mass": 0.33,
"alcohol": 6.0,
"picture": "https://i.imgur.com/qIq1OrC.png",
"amount": 502,
"userProducts": [],
"orderProducts": []
},
{
"id": 4,
"name": "Grimbergen Blonde",
"price": 132,
"mass": 0.33,
"alcohol": 6.7,
"picture": "https://i.imgur.com/OnioHd5.png",
"amount": 435,
"userProducts": [
{
"id": {
"productId": 2,
"userId": 4
},
"product": {
"id": 2,
"name": "Lav Premium",
"price": 73,
"mass": 0.33,
"alcohol": 4.9,
"picture": "https://i.imgur.com/T3gCAOE.png",
"amount": 1862,
"userProducts": [],
"orderProducts": []
},
"amountOfNewProducts": 32
}
],
"orderProducts": []
},
So basically even though i passed in 2 as product id the information will be written in product with id 4 just because the users id is 4. Any kind of a clue where I might me messing up would be appreciated.
You need to fix mappedBy = "user" in Product entity. It must be "product", like this:
#OneToMany(
mappedBy = "product",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<UserProduct> userProducts = new ArrayList<>();
Also check that you have correct #JoinColumn in UserProductId (ufortunately, you didn't put code for it to the question).

Entity Framework Mysql Slow Query

In my database I have 3 main classes which are Breeders, Horses and Races. These 3 tables have many-to-many relationships. A breeder can have multiple horses and a horse can have multiple breeders. Also a horse can enter multiple races and a race can have multiple horses entered. Now I want to query a breeders race stats. Using entity framework I have this line of code:
var races = DbContext.HorseBreeders
.Where(w => w.BreederId == someint)
.SelectMany(s => s.Horse.Races)
.ToList();
and this code generates this mysql query:
SELECT `w.Horse.Races`.`Id`, `w.Horse.Races`.`FinishTime`, `w.Horse.Races`.`Horse_Id`, `w.Horse.Races`.`Race_Id`
FROM `HorseBreeders` AS `w`
INNER JOIN `Horses` AS `w.Horse` ON `w`.`HorseId` = `w.Horse`.`Id`
INNER JOIN `RaceEntries` AS `w.Horse.Races` ON `w.Horse`.`Id` = `w.Horse.Races`.`Horse_Id`
WHERE `w`.`BreederId` = someint
and this query takes around 30 seconds.
Breeders table has 13k records
Horses table has 60k records
HorseBreeders table has 40k records
Races table has 110k records
RaceEntries table has 960k records.
In Mssql this same structure with a similar query was taking less than a second. But in Mysql its taking too much time. What am I doing wrong?
DbContext Classes:
public class Breeder
{
public int Id { get; set; }
[StringLength(50)]
public string Name { get; set; }
public virtual ICollection<HorseBreeder> Horses { get; set; }
}
public class Horse
{
public int Id { get; set; }
[StringLength(50)]
public string Name { get; set; }
public int? Father_Id { get; set; }
public virtual Horse Father { get; set; }
public int? Mother_Id { get; set; }
public virtual Horse Mother { get; set; }
public string BirthPlace { get; set; }
public DateTime? BirthDate { get; set; }
public virtual ICollection<HorseBreeder> Breeders { get; set; }
public virtual ICollection<RaceEntry> Races { get; set; }
public virtual ICollection<Horse> FatherChilds { get; set; }
public virtual ICollection<Horse> MotherChilds { get; set; }
}
public class HorseBreeder
{
public int HorseId { get; set; }
public Horse Horse { get; set; }
public int BreederId { get; set; }
public Breeder Breeder { get; set; }
}
public class Race
{
public int Id { get; set; }
public DateTime Time { get; set; }
public string Name { get; set; }
public virtual ICollection<RaceEntry> Horses { get; set; }
}
public class RaceEntry
{
public int Id { get; set; }
public int Race_Id { get; set; }
public virtual Race Race { get; set; }
public int Horse_Id { get; set; }
public virtual Horse Horse { get; set; }
public short? FinishTime { get; set; }
}
DbContext OnModelCreating:
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// Horse
builder.Entity<HorseBreeder>()
.HasKey(bc => new { bc.HorseId, bc.BreederId });
builder.Entity<HorseBreeder>()
.HasOne(bc => bc.Horse)
.WithMany(b => b.Breeders)
.HasForeignKey(bc => bc.HorseId);
builder.Entity<HorseBreeder>()
.HasOne(bc => bc.Breeder)
.WithMany(c => c.Horses)
.HasForeignKey(bc => bc.BreederId);
builder.Entity<Horse>()
.HasOne(p => p.Father)
.WithMany(p => p.FatherChilds)
.HasForeignKey(p => p.Father_Id);
builder.Entity<Horse>()
.HasOne(p => p.Mother)
.WithMany(p => p.MotherChilds)
.HasForeignKey(p => p.Mother_Id);
// RaceEntry
builder.Entity<RaceEntry>()
.HasOne(m => m.Race)
.WithMany(t => t.Horses)
.HasForeignKey(m => m.Race_Id);
builder.Entity<RaceEntry>()
.HasOne(m => m.Horse)
.WithMany(t => t.Races)
.HasForeignKey(m => m.Horse_Id);
}
Database create migration:
public partial class initial_create : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Breeders",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
Name = table.Column<string>(maxLength: 50, nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Breeders", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Horses",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
Name = table.Column<string>(maxLength: 50, nullable: true),
Father_Id = table.Column<int>(nullable: true),
Mother_Id = table.Column<int>(nullable: true),
BirthPlace = table.Column<string>(nullable: true),
BirthDate = table.Column<DateTime>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Horses", x => x.Id);
table.ForeignKey(
name: "FK_Horses_Horses_Father_Id",
column: x => x.Father_Id,
principalTable: "Horses",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "FK_Horses_Horses_Mother_Id",
column: x => x.Mother_Id,
principalTable: "Horses",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "Races",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
Time = table.Column<DateTime>(nullable: false),
Name = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Races", x => x.Id);
});
migrationBuilder.CreateTable(
name: "HorseBreeders",
columns: table => new
{
HorseId = table.Column<int>(nullable: false),
BreederId = table.Column<int>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_HorseBreeders", x => new { x.HorseId, x.BreederId });
table.ForeignKey(
name: "FK_HorseBreeders_Breeders_BreederId",
column: x => x.BreederId,
principalTable: "Breeders",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_HorseBreeders_Horses_HorseId",
column: x => x.HorseId,
principalTable: "Horses",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "RaceEntries",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
Race_Id = table.Column<int>(nullable: false),
Horse_Id = table.Column<int>(nullable: false),
FinishTime = table.Column<short>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_RaceEntries", x => x.Id);
table.ForeignKey(
name: "FK_RaceEntries_Horses_Horse_Id",
column: x => x.Horse_Id,
principalTable: "Horses",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_RaceEntries_Races_Race_Id",
column: x => x.Race_Id,
principalTable: "Races",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_HorseBreeders_BreederId",
table: "HorseBreeders",
column: "BreederId");
migrationBuilder.CreateIndex(
name: "IX_Horses_Father_Id",
table: "Horses",
column: "Father_Id");
migrationBuilder.CreateIndex(
name: "IX_Horses_Mother_Id",
table: "Horses",
column: "Mother_Id");
migrationBuilder.CreateIndex(
name: "IX_RaceEntries_Horse_Id",
table: "RaceEntries",
column: "Horse_Id");
migrationBuilder.CreateIndex(
name: "IX_RaceEntries_Race_Id",
table: "RaceEntries",
column: "Race_Id");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "HorseBreeders");
migrationBuilder.DropTable(
name: "RaceEntries");
migrationBuilder.DropTable(
name: "Breeders");
migrationBuilder.DropTable(
name: "Horses");
migrationBuilder.DropTable(
name: "Races");
}
}

Spring Data JPA joining two or more entites

I have three entities,
#Entity
public class Deck {
#Id
private int id;
private int number;
private String name;
#OneToMany(mappedBy = "deck")
private Set<Lab> labs;
//getter and setter methods
}
#Entity
public class Lab {
#Id
private int id;
private String name;
#ManyToOne
private Deck deck;
#OneToMany(mappedBy = "lab")
private Set<LabBooking> labBooking;
//getter and setter methods
}
#Entity
public class LabBooking {
#Id
private int id;
private Date startTime;
private Date endTime;
#ManyToOne
private Lab lab;
//getter and setter methods
}
Following is the LabRepository,
public interface LabRepository extends CrudRepository<Lab, Integer>{
#Query("SELECT l FROM Lab l JOIN l.labBooking lb WHERE l.deck.id = :deckId AND lb.startTime > '2016-02-24 15:00:00'")
List<Lab> findLabs(#Param("deckId") int deckId);
}
I am trying to retrieve the list of Labs in a deck which are occupied from a particular time.
When I execute the equivalent query (SELECT * FROM lab l JOIN lab_book lb ON l.id = lb.lab_id WHERE l.deck_id = 9999 AND lb.start_time > '2016-02-24 15:00:00') in MySQL, I am getting the following result
id name deck_id id end_time start_time lab_id
9001 Lab One 9999 5 2016-02-24 17:00:00 2016-02-24 16:00:00 9001
In the spring application I am getting the following result,
[{
"lab_id": 9001,
"lab_name": "Lab One",
"lab_booking": [{
"id": 4,
"start_time": "2016-02-24 15:00:00",
"end_time": "2016-02-24 16:00:00"
}, {
"id": 5,
"start_time": "2016-02-24 16:00:00",
"end_time": "2016-02-24 17:00:00"
}, {
"id": 3,
"start_time": "2016-02-24 14:00:00",
"end_time": "2016-02-23 14:30:00"
}]
}]
The Lab object was supposed to contain only the booking id 5, instead it shows all the ids.
If the sql query return 5 records, then the repository returns 5 Lab objects which are duplicate. What may be the issue?
Seems that your missing distinct.
SELECT distinct l FROM Lab l JOIN l.labBooking lb WHERE l.deck.id = :deckId AND lb.startTime > '2016-02-24 15:00:00'"

Adding information from one JsonBuilder object to another

As the title suggests, I'm trying to add information held in one JsonBuilder object to a second JsonBuilder object.
Currently I have this:
public String buildOneUser(DyveUserDTO user)
{
def userBuilder = new JsonBuilder()
userBuilder user.collect { usr ->
[
'Name': usr.userName,
'Allowance': usr.allowance,
'Total Holidays in Calendar': usr.totalHolidaysInCal,
'Holidays Booked': usr.numHolidaysBooked,
'Holidays Taken': usr.numHolidaysTaken,
'Holidays Remaining': usr.totalHolidaysLeft
]
}
def userHolidayBuilder = new JsonBuilder()
userHolidayBuilder user.holidayEvents.collect { usr ->
[
'Start Date': usr.startDate,
'End Date': usr.endDate,
'Days': usr.days
]
}
def userAndHolidays = userBuilder + userHolidayBuilder
return userAndHolidays.toPrettyString()
}
user.holidayEvents is a list of objects representing holidays and it could be empty or have any number of objects in it. This made me hesitant of doing something like:
def userBuilder = new JsonBuilder()
userBuilder user.collect { usr ->
[
'Name': usr.userName,
'Allowance': usr.allowance,
'Total Holidays in Calendar': usr.totalHolidaysInCal,
'Holidays Booked': usr.numHolidaysBooked,
'Holidays Taken': usr.numHolidaysTaken,
'Holidays Remaining': usr.totalHolidaysLeft
'Holiday': usr.holidayEvents[0].startDate
'Holiday': usr.holidayEvents[0].endDate
'Holiday': usr.holidayEvents[0].days
]
}
As I would only get the amount of holidays I write code for. It would also throw an exception if a user had no holidays and I told it look at usr.holidayEvents[1] as it's outside of the list range.
I've also tried nesting a .collect like this
def userBuilder = new JsonBuilder()
userBuilder {
'Name' user.userName,
'Allowance' user.allowance,
'Total Holidays in Calendar' user.totalHolidaysInCal,
'Holidays Booked' user.numHolidaysBooked,
'Holidays Taken' user.numHolidaysTaken,
'Holidays Remaining' user.totalHolidaysLeft,
'Holidays' user.holidayEvents.collect{ evt ->
[
'Start Date': evt.startDate,
'End Date': evt.endDate,
'Days': evt.days
]
}
}
But this returned all the keys except the Holidays key.
Any help would be greatly appreciated!
EDIT - My code now looks like this:
public String buildOneUser(DyveUserDTO user)
{
def userBuilder = new JsonBuilder()
userBuilder user.collect { usr ->
[
'Name': usr.userName,
'Allowance': usr.allowance,
'Total Holidays in Calendar': usr.totalHolidaysInCal,
'Holidays Booked': usr.numHolidaysBooked,
'Holidays Taken': usr.numHolidaysTaken,
'Holidays Remaining': usr.totalHolidaysLeft,
'Holidays': usr.holidayEvents.collect{ evt ->
[
'Start Date': evt.startDate,
'End Date': evt.endDate,
'Days': evt.days
]
}
]
}
}
EDIT 2 - Sample Code
Method to call:
public String buildOneUser(DyveUserDTO user)
{
def userBuilder = new JsonBuilder()
userBuilder {
Name:
user.userName
Allowance:
user.allowance
TotalHolidaysInCalendar:
user.totalHolidaysInCal
HolidaysBooked:
user.numHolidaysBooked
HolidaysTaken:
user.numHolidaysTaken
HolidaysRemaining:
user.totalHolidaysLeft
Holidays:
user.holidayEvents.collect { evt ->
[
'Start Date': evt.startDate,
'End Date' : evt.endDate,
'Days' : evt.days
]
}
}
return userBuilder.toPrettyString()
}
User to pass in:
class DyveUserDTO
{
String firstName = "Foo"
String userName = "FooBar"
Integer userID = 42
BigDecimal numHolidaysBooked = 3
BigDecimal numHolidaysTaken = 0
BigDecimal totalHolidaysInCal = 3
BigDecimal totalHolidaysLeft = 12
BigDecimal allowance = 12
List<HolidayObject> holidayEvents = []
}
Holiday objects to go in holidayEvents:
class HolidayObject
{
public Integer userID = 42
public String title = "Foo Holiday"
public String event = "Holiday"
public String amPm = "Full Day"
public String name = "Foo"
public LocalDateTime startDate = LocalDateTime.parse(2015-02-20T00:00:00)
public LocalDateTime endDate = LocalDateTime.parse(2015-02-20T00:00:00)
public BigDecimal days = 1
}
class HolidayObject
{
public Integer userID = 42
public String title = "Foo Holiday Pm"
public String event = "Holiday"
public String amPm = "Pm"
public String name = "Foo"
public LocalDateTime startDate = LocalDateTime.parse(2015-02-23T00:00:00)
public LocalDateTime endDate = LocalDateTime.parse(2015-02-24T00:00:00)
public BigDecimal days = 2
}
each just returns the list it's called upon, collect should be used for events. See the working code below:
import groovy.json.JsonBuilder
class UserEvent {
def start
def end
def days
}
class User {
def name
def events
}
def u1 = new User(name: 'u1', events: [new UserEvent(start: 0, end: 1, days: 1), new UserEvent(start: 0, end: 2, days: 2)])
def u2 = new User(name: 'u2', events: [new UserEvent(start: 0, end: 3, days: 3)])
def users = [u1, u2]
def userBuilder = new JsonBuilder()
userBuilder users.collect { usr ->
[
'name': usr.name,
'events': usr.events.collect { e ->
[
start: e.start,
end: e.end,
days: e.days,
]
}
]
}
print userBuilder.toPrettyString()
EDIT
Below is a working example:
import groovy.json.JsonBuilder
user = new DyveUserDTO()
def userBuilder = new JsonBuilder()
userBuilder {
Name user.userName
Allowance user.allowance
TotalHolidaysInCalendar user.totalHolidaysInCal
HolidaysBooked user.numHolidaysBooked
HolidaysTaken user.numHolidaysTaken
HolidaysRemaining user.totalHolidaysLeft
Holidays user.holidayEvents.collect { evt ->
[
'Start Date': evt.startDate,
'End Date' : evt.endDate,
'Days' : evt.days
]
}
}
println userBuilder.toPrettyString()
class DyveUserDTO {
String firstName = "Foo"
String userName = "FooBar"
Integer userID = 42
BigDecimal numHolidaysBooked = 3
BigDecimal numHolidaysTaken = 0
BigDecimal totalHolidaysInCal = 3
BigDecimal totalHolidaysLeft = 12
BigDecimal allowance = 12
List<HolidayObject> holidayEvents = [new HolidayObject(), new HolidayObject()]
}
class HolidayObject {
public Integer userID = 42
public String title = "Foo Holiday"
public String event = "Holiday"
public String amPm = "Full Day"
public String name = "Foo"
public String startDate = '2015-02-20T00:00:00'
public String endDate = '2015-02-20T00:00:00'
public BigDecimal days = 1
}
No colons : needed. See the sample here. Also I have no Joda dependency so replaced with String.