prolems with DB "save" with #LastModifiedDate and #LastModifiedBy - spring-data

I've setup Spring Data JPA Auditing as it is described in the docs. I think its configured correctly because on insert, i have all 4 fields (created, createdBy, modified, modifiedBy) filled in correctly.
Now the interesting part. On modification of the entity, everything seems to be running well. I debugged through all the Spring Auditing classes up to the point where in AuditingHandler.java this line:
LOGGER.debug("Touched {} - Last modification at {} by {}", new Object[] { target, defaultedNow, defaultedAuditor });
Looks completely ok. The target has the modified Fields set correctly and i cant see any issues BUT in the database, the two fields wont get updated. (value is still the creation date and user). So somehow it wont get saved. Of course all the other fields get updated including the JPA Version field. So everything but the modified* fields.
I am clueless. Anyone who can help me further how to debug that?
I am using Spring-Data-JPA in 1.9.0 and Spring 4.2.1 together with OpenJPA in the persistence backend.
UPDATE
I think i pinpointed the problem but there is a bug either in OpenJPA oder Spring-Data JPA.
The following class BeanWrapper.java from Spring-Data runs this code:
/*
* (non-Javadoc)
* #see org.springframework.data.mapping.PersistentPropertyAccessor#setProperty(org.springframework.data.mapping.PersistentProperty, java.lang.Object)
*/
public void setProperty(PersistentProperty<?> property, Object value) {
Assert.notNull(property, "PersistentProperty must not be null!");
try {
if (!property.usePropertyAccess()) {
ReflectionUtils.makeAccessible(property.getField());
ReflectionUtils.setField(property.getField(), bean, value);
return;
}
Method setter = property.getSetter();
if (property.usePropertyAccess() && setter != null) {
ReflectionUtils.makeAccessible(setter);
ReflectionUtils.invokeMethod(setter, bean, value);
}
} catch (IllegalStateException e) {
throw new MappingException("Could not set object property!", e);
}
}
JpaPersistentPropertyImpl (property) has usePropertyAccess attribute set to false, thus changing the modified field directly via reflection but this wont get the attribute marked dirty in OpenJPA. When modifying the value to true in the debugger, forcing to use the setter(), everything works fine.
So somewhere is a problem with the way OpenJPA <-> Spring Data interaction. Seems that OpenJPA doesnt like reflection attribute changes and insists on setter().
Is there a way to get this usePropertyAccess property to true?
CONCLUSION
Every journey needs to end. I found out that using #AccessType(AccessType.Type.PROPERTY) on my modified*/created* fields solves the issue. I am not quite sure that the current default -> AccessType.Type.Field is the most sensible one in Spring-Data... at least its not for OpenJPA. IMO this one is pretty hard to to find for non-experienced JPA/Spring developers. Perhaps a note in the documentation would be helpful. I have never used this AccessType property in my life and i am using Spring with OpenJPA for quite some time...

Related

Stored Procedure returns old value in ef core

I have an ASP.NET Core Web API. I am using raw SQL with a stored procedure to compute some values:
private TestContext context;
public TestRepository(TestContext tContext)
{
context = tContext;
}
public IEnumerable<test> GetTests(User user)
{
return context.tests.FromSql("EXECUTE dbo.test_GETALL {0}", user.code).ToList();
}
When I insert new record into my table, the result must be changed, but this code returns old values. How I fix this problem?
If TestContext is connected to EF, than that's the problem, or otherwise you may have your transaction badly configured.
I had a similar problem to this myself.
Check your startup.cs and make sure that service and repositories are not .AddSingleton.
These will need to be changed to .AddScoped (You might be able to use .AddTransient too)
services.AddSingleton<IYourService, YourService>(); //Needs to be AddScoped
services.AddSingleton<IYourRepository, YourRepository>(); //Also needs to be AddScoped
If you need more detail, here is my SO question that I believe relates to your situation.
Hope this helps!

Merging entity with Play! framework and JPA silently failed

I've been looking around and around without finding any topics related to my situation.
I'm using:
Play! framework v2.5.3 in Java
Hibernate EntityManager v5.1.0.Final
Hibernate JPA 2.1 API v1.0.0.Final
PostgreSQL 9.4
Here the route called with AJAX:
PUT /admin/entity/:id
Which is bound to:
controllers.Entity.update(id: Long)
Here how I handle the update request:
#play.db.jpa.Transactional
public Result update(final long id) {
EntityManager em = _jpa.em("default");
DynamicForm form = _formFactory.form().bindFromRequest();
models.Entity entity;
entity = em.find(models.Entity.class, id);
if (entity == null)
return badRequest();
entity.update(em, form);
em.merge(entity);
return ok();
The method update of Entity change values of the class attributes which are basically String attributes.
My issue: nothing get updated while still executing this piece of code.
I enable SQL log which only display the SELECT query corresponding to em.find() method call. Nothing related to an UPDATE query.
I've been using JPA/EntityManager with Play! for others projects (but with lower version of the framework) without facing this kind of problem.
Any idea why nothing get merged ?
I've been able to fix this issue by writing following piece of code inside
models.Entity.update:
em.getTransaction.begin();
Query query = em.createQuery("UPDATE entity SET value = :v WHERE id = :id");
query.setParameter("value", value);
query.setParameter("id", id);
query.executeUpdate();
em.getTransaction.commit();
But even if this is working, that's not the way how thing should be done... It
doesn't make coffee at all!
Edit: this solution do not work anymore....
I really don't know what I'm doing bad, if any body has an idea about this issue, you're help would be much appreciated.

Breeze: cannot execute _executeQueryCore until metadataStore is populated

I was using Breeze v1.1.2 that came with the Hot Towel template which has now been extended to form my project. I made the mistake of updating the NuGet package to the current 1.3.3 (I never learn). Anyway, all was well, and now not so much!
I followed the instructions in the release notes and other docs to change my BreezeWebApiConfig file to:
[assembly: WebActivator.PreApplicationStartMethod(
typeof(BreezeWebApiConfig), "RegisterBreezePreStart")]
namespace MyApp.App_Start {
public static class BreezeWebApiConfig {
public static void RegisterBreezePreStart() {
GlobalConfiguration.Configuration.Routes.MapHttpRoute(
name: "BreezeApi",
routeTemplate: "breeze/{controller}/{action}"
);}}}
And the config.js file (which provides the serviceName to the EntityManager constructor) to:
var remoteServiceName = 'breeze/breeze'; // NEW version
//var remoteServiceName = 'api/breeze'; // OLD version
And my BreezeController if you're interested:
[BreezeController]
public class BreezeController : ApiController
{
readonly EFContextProvider<MyDbContext> _contextProvider =
new EFContextProvider<MyDbContext>();
[HttpGet]
public string Metadata()
{
return _contextProvider.Metadata();
}
[HttpGet]
public IQueryable<SomeItem> SomeItems()
{
// Do stuff here...
}
}
Now I get the "cannot execute _executeQueryCore until metadataStore is populated" error.
What am I missing here?
EDIT:
I perhaps left out the part you needed... Above in the SomeItems() method, the stuff that actually gets done is a call to the GetMeSomeData() method in the MyDBContext class. This method makes the following call to a stored procedure to get the data.
public virtual ObjectResult<SomeItem> GetMeSomeData(string inParam)
{
var p = new object[] { new SqlParameter("#inParam", inParam) };
var retVal = ((IObjectContextAdapter)this).ObjectContext.ExecuteStoreQuery<SomeItem>("exec GetData #SN", p);
return retVal;
}
Now given my limited understanding, the call to Metadata() is not failing, but I don't think it has any idea what the entity model is when coming back, even though somewhere along the line, it should figure that out from the entity model I do have (i.e. SomeItem)? The return string from Metadata() doesn't have any information about the entity. Is there a way to make it aware? Or am I just completely off in left field playing with the daisies?
Hard to say based on this report. Let's see if Breeze is right.
Open the browser debugging tools and look at the network traffic. Do you see an attempt to get metadata from the server before you get that error? If so, did it succeed? Or 404? Or 500? What was the error?
I'm betting it didn't even try. If it didn't, the usual reason is that you tried some Breeze operation before your first query ... and you didn't ask for metadata explicitly either. Did you try to create an entity? That requires metadata.
The point is, you've got to track down the Breeze operation that precipitates the error. Sure everything should just work. The world should be rainbows and unicorns. When it isn't, we heave a sigh, break out the debugger, and start with the information that the error gave us.
And for the rest of you out there ... upgrading to a new Breeze version is a good thing.
Happy coding everyone.
Follow-up to your update
Breeze doesn't know how you get your data on the back-end. If the query result has a recognizable entity in it, Breeze will cache that. It's still up to you in the query callback to ensure that what you deliver to the caller is something meaningful.
You say that you're server-side metadata method doesn't have any idea what SomeItem is? Then it's not much use to the client. If it returns a null string, Breeze may treat that as "no metadata at all" in which case you should be getting the "cannot execute _executeQueryCore until metadataStore is populated" error message. Btw, did you check the network traffic to determine what your server actually returned in response to the metadata request (or if there was such a request)?
There are many ways to create Metadata on the server. The easiest is to use EF ... at least as a modeling tool at design time. What's in that MyDbContext of yours? Why isn't SomeItem in there?
You also can create metadata on the client if you don't want to generate it from the server. You do have to tell the Breeze client that you've made that choice. Much of this is explained in the documentation "Metadata Format".
I get the feeling that you're kind of winging it. You want to stray from the happy path ... and that's cool. But most of us need to learn to walk before we run.

How do I resolve "No views were found in assemblies or could be generated for Table"?

I am working with a database first model in Entity Framework 5 and when I attempt to add a row, I get the following error:
"No views were found in assemblies or could be generated for Table 'ui_renewals'."
The table exists in my EDMX and the template generated a ui_renewals class. I've deleted the table from the EDMX and added it again using the Update Model from Database option and I get the same error. Creating a separate connection for it resolves the issue, but that seems like a less-than-ideal solution (more like a kludge) not to mention it makes it more difficult to maintain in the future.
Any ideas on how to fix this so that I can add or update (I've tried both) a row in ui_renewals?
Here is the code I'm currently using - only difference before was using db as a DBContext instead of ui (yes, receipt is misspelled - gotta love legacy stuff)
[HttpPost]
public bool UpdateTeacher(string login_id, string password, UIRenewal data)
{
if (ModelState.IsValid)
{
// map from UIRenewal VM to ui_renewal
ui_renewals Renewal = Mapper.Map<UIRenewal, ui_renewals>(data);
// check to see if this is a new entry or not
var tmp = ui.ui_renewals.Find(Renewal.reciept);
if (tmp == null)
ui.ui_renewals.Add(Renewal);
else
{
// mark as modified
db.Entry(Renewal).State = EntityState.Modified;
}
// save it
try
{
ui.SaveChanges();
}
catch (DBConcurrencyException)
{
return false;
}
return true;
}
return false;
}
I should mention that I do have a view in the model (v_recent_license).
I know this is a very old question, however as I haven't found any other topics like this, I'll post my answer.
I have had the same Exception thrown. I found that, in a failed attempt to optimize EF performance, following the advices found here, I left behind this piece of code in EF .edmx code-behind:
<EntityContainerMapping StorageEntityContainer="XXXModelStoreContainer" CdmEntityContainer="YYYEntities" GenerateUpdateViews="false">
I removed the GenerateUpdateViews="false" string, and all is working again.
(The Exception message is a little misleading in my opinion).

Update a table using JPA in Play Framework

I'm trying to update a table using JPA
EntityManager em=JPA.em();
EntityTransaction entr = em.getTransaction();
try{
if(!entr.isActive())
entr.begin();
Tblrecordtypefields updateTblrecordtypes = em.find(Tblrecordtypefields.class,9);
updateTblrecordtypes.setFieldlabel("JPATest");
em.getTransaction().commit();
}finally
{
if(entr.isActive())
entr.rollback();
}
i'm getting the error
NullPointerException occured : null at
updateTblrecordtypes.setFieldlabel("JPATest");
What should i do.
I see some possible issues in there:
First, Play manages the transactions on it's own. A transaction is created at the beginning of the request and committed (rollback if exception) at the end. You are trying to force your way into it, that's not recommended. To manage the entity, just do an entity.save() to mark it as "to be saved" and don't do tht to ignore any changes.
Second, if you are using the Model class in Play (as you should) you can use the "find" and "findById" methods provided by this class. This is recommened, instead of using the EntityManager directly.
See the documentation for more information.
Basically, redo your code to follow the Play way, to avoid problems :)
EDIT: as a clarification, I'm not really answering your question on why you get the NPE, but I think that as you are forcing your way into the settings of the framework you might (maybe not!) be seeing unexpected artifacts that will dissapear once you fix your code to follow convention.
If after that you still have the error let us know :)
This means that there is no row with ID 9 in the database table mapped by the entity Tblrecordtypefields.
BTW: I find it very questionable to commit a transaction in a method which is not necessary the one that started the transaction.
I have changed my code as below
Tblrecordtypefields updateTblrecordtypeFields = Tblrecordtypefields.findById(9);
updateTblrecordtypeFields.setFieldlabel("Test");
validation.valid(updateTblrecordtypeFields);
if(validation.hasErrors())
{
updateTblrecordtypeFields.refresh();
}
else
{
updateTblrecordtypeFields.save();
}
in my model class
public void setFieldlabel(String fieldlabel) {
this.fieldlabel = fieldlabel;
}
Works Fine.....