I'm using SpringBoot 2.2.6 with JPA 2 and Hibernate 5 and I have the following problem.
I have a #Service similar to following one:
public class Service {
#Autowired OtherService otherService;
#Autowired SaveService saveService;
public doIt() {
Entity entity = otherService.findById(id) // retrieve the entities
entity.getSubEntities().add(subEntity) // should add a row to certain table (subentity is a 1:n relationship)
saveService.update(entity); // the row is added, I can see it on phisical DB
entity = otherService.findById(id); // the DTO subentity doesn't contain the row added
}
}
public class OtherService {
#Autowired JpaRepository jpaRepository;
public Entity findById(Integer id) {
return jpaRepository.findById(id);
}
}
public class SaveService {
#Autowired JpaRepository jpaRepository;
public void update(Entity entity) {
jpaRepository.save(entity);
}
}
As I wrote in the comments, the first find extract an entity with a subEntity (1:n relationship) correctly loaded. The second row save a new line in the db and the third line retrieve the Entity again.
If I debugging the app, when I arrive to the third row I can see the new line added to the DB but when I fire the find the entity doesn't have the subentity (a list) correctly loaded.. It has one element less than the DB..
Why does this happen? I remove the #Transactional annotation everywhere to avoid similar error (the order of query and so on..)
Thank you.
Related
I want to save both child and parent entities whenever a POST call is made. I have an Item entity with a one to one mapping to a parent table Attribute:
#Entity
#Table(name="Item")
#JsonIgnoreProperties(ignoreUnknown = true)
public class Item
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="id")
private Long id;
#OneToOne(fetch=FetchType.LAZY)
#JoinColumn(name="attr_id")
private Attribute attribute;
#OneToMany(mappedBy = "item", cascade = CascadeType.ALL, orphanRemoval=true)
private List<ValueSet> valueSets = new ArrayList<>();
// Other fields, getters, setters, overriding equals and hashcode using Objects.equals() and Objects.hashCode() for all the fields, helper for adding and removing ValueSet
}
The Attribute entity looks like this:
#Entity
#Table(name="Attribute")
#JsonIgnoreProperties(ignoreUnknown = true)
public class Attribute
{
#Id
#Column(name="id")
private Long id;
// Other fields, getters, setters, NOT overriding equals hashCode
}
Whenever an Item gets saved I need the Attribute to get saved as well. I've my postman sending JSON POST data as follows:
{
"attribute":{
"id":"6"
},
"valueSets":[
{
"value":"basic"
}
]
}
My handler looks like this:
#PostMapping("/item")
public void postItems(#RequestBody Item item)
{
itemRepository.save(item);
}
ItemRepository is just a one liner with #Repository annotation:
public interface ItemRepository extends CrudRepository<Item, Long>
When I try to save the Item I run into - Cannot insert the value NULL into column 'attr_id', table 'Item'; column does not allow nulls. INSERT fails.
I can't figure out why is it unable to take the id value of 6 that I am supplying as part of my POST invocation. The id value 6 already exists on the Attribute table. I have also tried making the relationship bi-directional using mappedBy and CASCADE.ALL but still get the same error.
Any thoughts/suggestions on what I'm messing/missing? Also, is there a better approach to handle nested entities? Should I try to save each of them individually? In that case can the #RequestBody still be the parent entity?
I have built an example project, and try to replicate your situation, not successful. I am able to insert the "item" without any issue.
I placed the project under this repository https://github.com/hepoiko/user-5483731-1
Hope this help you to troubleshooting further or let me know If I miss anything in there.
I'm trying to learn EF 6 Code-first in WPF by following some tutorials. Since I'm familiar with model-first I can understand most parts except I've found ContextInitializer a little confusing. I defined a ContextInitializer like this code:
public class ContextInitializer : DropCreateDatabaseIfModelChanges<Context>
{
protected override void Seed(Context context)
{
var customers = new List<Customer>
{
new Customer{Name="Jane",Phone="2238718"},
new Customer{Name="David",Phone="43245608"},
new Customer{Name="Mike",Phone="90814417"}
};
customers.ForEach(cu => context.Customers.Add(cu));
context.SaveChanges();
}
}
and this is my Context class:
public class Context : DbContext
{
public Context()
: base("MVVM")
{
}
public DbSet<Customer> Customers { get; set; }
}
and It created a database at first run which I think it's weird because this class has zero refrences. Since Seed method doesn't fire again, I can't understand how this works.
Can someone explain to me how my ContextInitializer with zero reference created a database?
Does the following section exist in your App.Config?
<contexts>
<context type="(your name space).Context, MVVM">
<databaseInitializer type="(your name space).ContextInitializer, MVVM" />
</context>
</contexts>
If it is, the program knows where to look to find the ContextInitializer. If the database already exists and the tables in the database already match those of the POCO/model classes, nothing happens. If the model has changed or the database doesn’t exist, this class will be invoked, resulting in the database being seeded with your data.
I have a problem with my function which is supposed to save data to database, function creates a new object which includes other objects. I am able to save and fetch objects which contain only primitive data types and Strings to Database , so the database and system works in this case. I am using JavaEE and EntityManager (persist).
Any help?
You can define a cascade type on the parent entity. Have a look on the Java EE tutorial (http://docs.oracle.com/javaee/6/tutorial/doc/bnbqa.html#bnbqm)
see the principal below
#Entity
public class Customer {
#OneToMany(cascade=CascadeType.ALL, mappedBy="customer")
public Set<Order> getOrders() {
return orders;
}
...
}
#Entity
public class Order {
#OneToOne
Customer customer;
...
}
I am new to GAE and Datastore
I am trying to insert different types of entities in GAE Datastore using JPA.
For example i have to insert Employee,EmployeePersonalInfo(Having a Employee Key),EmployeeAddressInfo(Having a EmployeePersonalInfo key). Here i am not creating any foreign key relationships between entities.My entities will looks like follows
public class Employee{
private String name;
private Key key;
}
public class EmployeePersonalInfo{
private String emailAddress;
private Key key;
private Key employeeKey;
}
public class EmployeeAddressInfo{
private String cityName;
private Key key;
private Key employeePersonalInfoKey;
}
i am trying to insert around 5 record on each table like
public class EmployeeController{
/*This method will be called for 5 times*/
public void insertEmployeeDetails(Employee emp,EmployeePersonalInfo perInfo,EmployeeAddressInfo addressInfo){
employeeDao.save(emp);
employeePersonalInfoDao.save(perInfo);
employeeAddressInfoDao.save(addressInfo);
}
}
Every time When a call goes to Save method of the DAO classes i will open the EntityManager object , and close after the operation.
public void save(Employee emp){
EntityManager em = EMFService.get().createEntityManager();
em.save(emp);
em.close();
}
Here sometimes i am getting an exception like
Caused by: java.lang.IllegalArgumentException: cross-group transaction need to be explicitly specified, see TransactionOptions.Builder.withXG
I have seen my so many solutions to this problem but i am not able to understand what is the real problem and solution. Please help me
I get this error when I attempt to save to the database.
In the Controller I have the Edit HttpPut
public ActionResult EditSubject(Models.xxxx model)
{
//Database Model Class
SubjectDB subjectdb = new SubjectDB();
// Name of DB Access in Web.config
BeaconDBEntities db = new BeaconDBEntities();
if (ModelState.IsValid)
{
subjectdb.SubjectId = model.SubjectId;
db.SubjectDBs.Add(subjectdb); --> Pops InvalidOperationsException
db.SaveChanges();
}
In Models folder is the model for the database table
SubjectDB.cs
namespace xxx.Models
{
public class SubjectDB
{
public string SubjectId { get; set;}
}
public class BeaconDBEntities: DbContext
{
public DbSet<SubjectDB> SubjectDBs { get; set; }
}
}
Web.config is the connect string for the database
<coneectionStrings>
<add name="BeaconDBEntities" ...............
</connectionStrings>
The first thing I see is that your connection string name 'BeaconDBEntites' does not match your DbContext inherited class name 'BeaconDBEntities' (you are missing an 'i' in the word Entities). Try changing that and see if it fixes it.
When you edit your data then i think you don't need to write code like this when your useing entity framework it's below code
db.SubjecDBs.Add(subjectdb);
db.SaveChanges();
first when you update your data then first your get your data with your id like this it's below
and your create object your entity class. your entity class is your table like below
SubjecDBs objsub=new SubjecDBs();
var data =db.db.SubjecDBs.where(x=>x.SubjectID==ID).ToList();
then you match your data which is you wont to update like below
objsub.SubjecName=data[0].SubjecName
and you match your field which you wont to update then your write below code like this
db.SaveChanges();
i think this will help you...