Spring Boot JPA : identifier of an instance of bingo.model.Group was altered from 1702 to null - spring-boot

I have a Short Question:
Last Save is working(Last Save will be Update).
But First Save is not working.(First Save will be Insert)
I can't insert this way, how is it possible?
#GetMapping(value = "/delete/{id}")
public String delete(#PathVariable BigInteger id, Model model) {
try {
Group group = groupService.findById(id);
group.setId(null);
group.isLog(true);
// This Save will be Insert Data
groupService.save(group);
group = groupService.findById(id);
group.isLog(true);
//This Save will be Update Data
groupService.save(group);
return "redirect:/accountsGroup/";
} catch (Exception ex) {
return "masters/accountsInfo/groups/index";
}
}

You can't just set the ID null.
The entity is in a managed state and will not be new just because you set the ID to null.
The proper way would be to clone the entity state in a new instance.
You could also try to detach the entity (EntityManager.detach) and then set the ID to null. Maybe it will insert a new row. But as I said this is not the way you should do that.
Read more about entity states here: https://vladmihalcea.com/a-beginners-guide-to-jpa-hibernate-entity-state-transitions/

Related

Spring + Hibernate: Select from repository while it's updating an entry

I've just run into a problem, where I'm trying to select (repo.findById(id)) an object from the database using it's id, while it's being updated (Hibernate's onPreUpdate and onPostUpdate methods in PreUpdateEventListener and PostUpdateEventListener interfaces), but it's throwing a NullPointerException for me.
Perhaps it's easier if I explain it this way:
I have an object with status "PENDING", if it's being changed to "CONFIRMED", I want to check what the previous status was in the onPreUpdate method by doing this:
#Override
public boolean onPreUpdate(PreUpdateEvent preUpdateEvent)
{
final Object entity = preUpdateEvent.getEntity();
if (entity instanceof Status)
{
Status status = (Status) entity;
//Method below throws NullPointerException
Status statusFromRepo = statusRepo.findByStatusId(status.getStatusId());
}
return false;
}
But since statusRepo is already updating this object in the database, am I not able to do anything to get the object BEFORE it's updated? PreUpdateEvent contains the already "updated" version which is going to be saved in the database.

How do entity framework handle concurrency access,when issuing multiple delete & create opeartions

I have the following method inside my asp.net mvc, and i am trying to understand how will entity framework behave when multiple users access the same method :-
public int changeDeviceSwitch(int fromID , int toID)
{
var currentdevices = IT.ITSwitchPorts.Where(a => a.SwitchID == fromID);
int count = 0;
foreach (var d in currentdevices)
{
tms.ITSwitchPorts.Remove(d);
count++;
}
foreach (var d in currentdevices)
{
ITSwitchPort tsp = new ITSwitchPort() { SwitchID = toID, TechnologyID = d.TechnologyID, PortNumber = d.PortNumber };
IT.TMSSwitchPorts.Add(tsp);
}
IT.SaveChanges();
return count;
}
The above method, will mainly, retrieve all the records that have switchID = fromID, then remove all these records and add new records with new switchID.
so my question is what will happen if multiple users access the same method at the same time? as i understand that entity framework can handle the concurrent access in this way as follow:-
-userA call the method
-userB calls the same method
-userA retrieve all the records, delete, then add new records , save.
-userB retrieve all the records , delete, add new records. but when userB reach the saveChnages() ,
entity framework will raise a DbUpdateConcurrencyException when it try to delete a record that no more exists ? so is this what will happen. ?
can anyone advice please?
Thanks
General approach to locking in EF is to use Optimistic locking.
EF Locking docu
SO example
-userB retrieve all the records , delete, add new records. but when userB reach the saveChnages() , entity framework will raise a
DbUpdateConcurrencyException when it try to delete a record that no
more exists ? so is this what will happen. ?
Yes this is what will happen IF you have declared a Concurrency field on the record.
eg
public virtual byte[] RowVersion { get; set; }

How do I update Object with Spring Data and MongoDB?

How do I update Object with Spring Data and MongoDB?
do I just do a template.save()?
public Person update( String id, String Name )
{
logger.debug("Retrieving an existing person");
// Find an entry where pid matches the id
Query query = new Query(where("pid").is(id));
// Execute the query and find one matching entry
Person person = mongoTemplate.findOne("mycollection", query, Person.class);
person.setName(name);
/**
* How do I update the database
*/
return person;
}
If you read the javadoc for MongoOperations/MongoTemplate you will see that
save()
performs an:
upsert()
So yes you can just update your object and call save.
You could probably do both 'find' and 'update' operations in one line.
mongoTemplate.updateFirst(query,Update.update("Name", name),Person.class)
You can find some excellent tutorials at
Spring Data MongoDB Helloworld
You can just use template.save() or repository.save(entity) methods for this. But mongo has also Update object for this operations.
For example:
Update update=new Update();
update.set("fieldName",value);
mongoTemplate.update**(query,update,entityClass);
Below code is the equivalent implementation using MongoTemplate for update operation.
public Person update(Person person){
Query query = new Query();
query.addCriteria(Criteria.where("id").is(person.getId()));
Update update = new Update();
update.set("name", person.getName());
update.set("description", person.getDescription());
return mongoTemplate.findAndModify(query, update, Person.class);
}

How i can force the entity framework to raise a unique exception if the Unique key constraint has been violated on thr sql server database

I have a table named countries and i define the country_name field to be unique by creating a “Index/Key” of type “Unique Key” on sql servwer 2008 r2.
But currently if the user insert a country_name value that already exists on my asp.net mvc3 application, then an exception of type “System.Data.Entity.Infrastructure.DbUpdateException” will be raised , which is very general.
So is there a way to define a specific exception in case the unique constraint has been violated ??? rather than just raising the general “System.Data.Entity.Infrastructure.DbUpdateException” exception?
BR
Most likely, thought I can't test it at the moment, the inner exception of DbUpdateException is probably an exception about a duplicate or foreign key constraint. More importantly, you have an opportunity to not throw any exceptions by checking to see if a country already exists. Two ways I can think of are to; check and see if the country already exists by doing a simple select, and if it doesn't, doing an insert/add or write a stored procedure that and do a select/insert or merge and return any value(s) you want back.
Update
(this is example code to demonstrate the logic flow of events and not good programming practice, specially by catching all excepts)
Exception Logic
public AddCountry(string countryTitle)
{
using (var db = new DbContext(_connectionString)
{
try
{
// Linq to (SQL/EF)-ish code
Country country = new Country();
country.ID = Guid.NewGuid();
country.Title = countryTitle;
db.Countrys.Add(country);
db.SubmitChanges(); // <--- at this point a country could already exist
}
catch (DbUpdateException ex)
{
// <--- at this point a country could be delete by another user
throw Exception("Country with that name already exists");
}
}
}
Non-Exception Logic
public AddCountry(string countryTitle)
{
using (var db = new DbContext(_connectionString)
{
using (TransactionScope transaction = new TransactionScope())
{
try
{
Country country = db.Countries
.FirstOrDefault(x => x.Title = countryTitle);
if (country == null)
{
country = new Country();
country.ID = Guid.NewGuid();
country.Title = countryTitle;
db.Countrys.Add(country);
db.SubmitChanges(); // <--- at this point a country
// shouldn't exist due to the transaction
// although someone with more expertise
// on transactions with entity framework
// would show how to use transactions properly
}
}
catch (<someTimeOfTransactionException> ex)
{
// <--- at this point a country with the same name
// should not exist due to the transaction
// this should really only be a deadlock exception
// or an exception outside the scope of the question
// (like connection to sql lost, etc)
throw Exception("Deadlock exception, cannot create country.");
}
}
}
}
Most likely the TransactionScope(Transaction transactionToUse) Constructor would be needed and configured properly. Probably with an Transactions.IsolationLevel set to Serializable
I would also recommend reading Entity Framework transaction.

Auditing in Entity Framework

After going through Entity Framework I have a couple of questions on implementing auditing in Entity Framework.
I want to store each column values that is created or updated to a different audit table.
Right now I am calling SaveChanges(false) to save the records in the DB(still the changes in context is not reset). Then get the added | modified records and loop through the GetObjectStateEntries. But don't know how to get the values of the columns where their values are filled by stored proc. ie, createdate, modifieddate etc.
Below is the sample code I am working on it.
// Get the changed entires( ie, records)
IEnumerable<ObjectStateEntry> changes = context.ObjectStateManager.GetObjectStateEntries(EntityState.Modified);
// Iterate each ObjectStateEntry( for each record in the update/modified collection)
foreach (ObjectStateEntry entry in changes)
{
// Iterate the columns in each record and get thier old and new value respectively
foreach (var columnName in entry.GetModifiedProperties())
{
string oldValue = entry.OriginalValues[columnName].ToString();
string newValue = entry.CurrentValues[columnName].ToString();
// Do Some Auditing by sending entityname, columnname, oldvalue, newvalue
}
}
changes = context.ObjectStateManager.GetObjectStateEntries(EntityState.Added);
foreach (ObjectStateEntry entry in changes)
{
if (entry.IsRelationship) continue;
var columnNames = (from p in entry.EntitySet.ElementType.Members
select p.Name).ToList();
foreach (var columnName in columnNames)
{
string newValue = entry.CurrentValues[columnName].ToString();
// Do Some Auditing by sending entityname, columnname, value
}
}
Here you have two basic options:
Do it at the database level
Do it in the c# code
Doing it at the data base level, means using triggers. In that case there is no difference if you are using enterprise library or another data access technology.
To do it in the C# code you would add a log table to your datamodel, and write the changes to the log table. When you do a save changes both the changes to the data and the information which you wrote to the log table would be saved.
Are you inserting the new record using a stored proc? If not (i.e. you are newing up an object, setting values, inserting on submit and then saving changes the new object id will be automatically loaded into the id property of the object you created. If you are using a stored proc to do the insert then you need to return the ##IDENTITY from the proc as a return value.
EX:
StoreDateContext db = new StoreDataContext(connString);
Product p = new Product();
p.Name = "Hello Kitty Back Scratcher";
p.CategoryId = 5;
db.Products.Add(p);
try
{
db.SaveChanges();
//p.Id is now set
return p.Id;
}
finally
{
db.Dispose;
}

Resources