How to check if exists when using CrudRepository#getOne() - spring

I have a Document entity. To edit a document you must acquire a DocumentLock.
Request API to edit a document looks like below. edit=true allows to fetch the record from database with 'FOR UPDATE`.
GET /api/document/123?edit=true
In Back end side, we do like this (of course over simplified),
Document document = documentRepository.getOne(documentId) //<--- (1)
if(document == null){ //<--- (2) This is always false
//Throw exception
}
DocumentLock dl = DocumentLock.builder()
.lockedBy(user)
.lockedAt(NOW)
.document(document)
.build()
documentLockRepository.save(dl);
We are using getOne() because we do not need to fetch whole document from database, we are just creating a relation with DocumentLock object.
Question is, how to ensure the document actually exists? Because getOne() will always return the proxy and I do not see any obvious way to check if the record exists in databse.
Versions:
spring-data-jpa: 2.2.6.RELEASE
hibernate: 5.4.12
Update: removed additional questions.

Use findById or existsById. Yes they do access the database. That is the point of it, isn't it?
getOne is explicitly for use cases where you already know the entity exists and only need the id wrapped in something that looks like the entity.

If your repository returning value or its transactional management is confusing, you should check your repository codes and entity class design even session configurations that used for querying or even your Datastore design because everything looks fine in this code fragment

Related

Change record owner in Dynamics CRM plugin

I am writing a Post PLugin changing the owner. When the owner has a substitution manager, the owner is changed to the substitution manager. I tried a service.Update and an AssignRequest, but these throw an exception.
When I post the request my entity cannot update (and then throws "The request channel time out while waiting for reply after 10:00:00"). But like I see there is no recursion, because when I logged it I have only one repetition of log and it has stopped before or on line with update.
var assignedIncident = new AssignRequest
{
Assignee = substManagerRef, //get it throw another method, alreay checked in test it`s correct
Target = new EntityReference ("incident", incedentId)
};
service.Execute(assignedIncident);
I tried to write target in another way
Target = postEntityImage.ToEntityReference()
I tried to write simple update but the problem is the same.
Entity incident = new Entity("incident" , incidentId);
incident["ownerid"] = substManagerRef:
service.Update(incident);
Can somebody help me with that? Or maybe show the way to solve it)
The plugin is triggering itself and gets in a loop. The system only allows a maximum of 8 calls deep within plugins and that is the reason it throws an error and rolls back the transaction.
To solve this issue redesign your plugin in the following way:
Register your plugin on the Update message of your entity in the PreValidation stage.
In the plugin pick up the Target property from the InputParameters collection.
This is an Entity type. Modify or set the ownerid attribute on this Entity object.
That is all. You do not need to do an update, your modification is now passed into the plugin pipeline.
Note: for EntityReference attributes this technique only works when your plugin is registered in the PreValidation stage. For other regular attributes it also works in the PreOperation stage.

setObjectId is not working

I wonder if is possible to assign an id when an item is created with parse:
ParseObject parseWord = new ParseObject(DataBaseHelper.TABLE_WORD);
parseWord.setObjectId(idRow);
parseWord.put(Word.NAME, word.getName());
parseWord.put(Word.TYPE, word.getType());
parseWord.put(Word.TRANSLATE, word.getTranslate());
parseWord.put(Word.EXAMPLE, word.getExample());
parseWord.put(Word.NOTE, word.getNote());
parseWord.put(Word.SYNC_AT, today);
parseWord.saveInBackground();
This code is not working, it doesnt save the item in the server. If I delete the setObjectId(idRow); it works. What am I doing wrong?.
Is there anyway to know when the saveInBackground is done?
Thanks
According to the ParseObject.setObjectID() API doc:
Setter for the object id. In general you do not need to use this.
However, in some cases this can be convenient. For example, if you are
serializing a ParseObject yourself and wish to recreate it, you can
use this to recreate the ParseObject exactly.
Also from the API doc:
An object id is assigned as soon as an object is saved to the server.
A reason, as the quote suggests, you might need to set the object ID is if you, wish to do something like save the fields of a parse object to a file. If you wanted to take the fields from your file and recreate a parse object, THEN you'd need to set it, as that's not done for you if you're not saving it to the server and just using an instance of the object for purposes internal to your application.

should a validation function access the repository directly?

I have the following in my application:
Action Orm entity (From telerik open access)
Repository(Of Action)
AppService(Holds an instance of the repository)
when I need to save an instance, I send the instance to the AppService. the AppService then calls a validator to validate the instance to save. the validator is based on http://codeinsanity.com/archive/2008/12/02/a-framework-for-validation-and-business-rules.aspx
(full code on https://github.com/riteshrao/ncommon)
so basically my save function in the AppService looks like this
Public Sub AddAction(ByVal Item As Data.Model.Action)
Contract.Requires(Of ArgumentNullException)(Item IsNot Nothing, "Item is nothing.")
Dim validateResult As Rules.ValidationResult = _ActionValidator.Validate(Item)
If Not validateResult.IsValid Then
Throw New Validation.ValidationException(validateResult)
End If
Try
_ActionRepository.Add(Item)
_unitOfWork.SaveChanges()
Catch ex As Exception
_unitOfWork.ClearChanges()
Throw New DataServiceException(ex.Message, ex)
End Try
End Sub
for checking properties of the Action item the sample code works great. my question begins when i need to make sure that the same action is not added twice to the DB for the same customer (ie. id is difference, name is the same and customer is the same)
as I see it I have a few options:
option 1: check for a duplicate action using something like
function(validatedItem) item.Customer.Actions.Any(function(item) item.id<>validatedItem.id andalso item.name=validatedItem.name))
basically I go from the action being saved back to the customer and then back to all his actions and check if any action exists with a different id and same name
the down sides are:
a. for this to work, when accessing the customer property of the item, the entire customer object is read from DB which is redundant in this case
b. the Any function is being evaluated on the client as item.Customer.Actions returns IList(Of Action)
Option 2: let the validation class have access to the action repository. then i could simply do something like
'assume I already have validatedItem
repository.Any(function(item) item.id<>validatedItem.id and item.customerid=validatedItem.customerid and item.name=validatedItem.name)
this will result in an Exists query being sent to the DB but the downside(?) is that the validation framework should not access the repository directly (as far as I have seen in the very few examples i could find that do use validation and ORM)
Option 3: let the validation class have access to the AppService and use the AppService to check for existence of a duplicate.
problems:
a. I create a circular reference (AppService->Validation Class->AppService)
b. I need to create a lot of useless functions in the AppService for loading items based on criteria that is only relevant for the validation
Any ideas what is the best course here?
The simplest is not to check duplicates in the database from your domain.
When a collection of entities is part of you aggregate then it is a non-issue since you would not permit the duplicate to be added to the collection. Since the aggregate is stored as a whole you would never run into the problem.
For scenarios where you do not want a duplicate, say, e-mail address and no collection of the entities is represented by an aggregate (such as the Users in a system) you can just let the database enforce the uniqueness. Simply pick up the exception and report back. In many instances your validation would not be able to enforce the uniqueness simply because it doesn't have/implement the required locks that a database system would have.
So I'd simply leave that up to the database.

Spring JSON merge

I'm updating a record from a form over AJAX. I have a JSON object that maps to my entity, and my controller method is:
#RequestMapping(value = "/vendors", method = RequestMethod.POST)
public ResponseEntity<String> saveVendorsJson(#RequestParam String vendor) {
Vendor v = Vendor.fromJsonToVendor(vendor);
if (v.merge() == null) {
v.persist();
}
return new ResponseEntity<String>(HttpStatus.OK);
}
I expected from the documentation that v.merge() will return null if it didn't find an existing record by the object's 'id' field to merge with, and in that case I want to persist it as a new Vendor object.
What's happening is, despite my JSON having an 'id' field value that matches an existing record, I'm ALWAYS inserting a new record with my updated goods from the browser.
I'm aware I'm having the POST method pull double-duty here, which isn't strictly RESTful. In theory, this is simpler for me (though of course that's turning out not to be the case).
I believe this is a Hibernate thing. Hibernate will not "merge" if it doesn't know it already exists. I think what I have done in the past is to do a lookup, then a persist. I think if you try to just merge something coming in off the wire you would get a Primary Key Collision, or something similar. I believe Hibernate has some sort of "dirty" flag internal to indicate if you are creating or editing an existing object.
There also used to be a way in raw-Hibernate to do a soft-lookup, basically tell Hibernate "look, I have this object, I don't want to do a SELECT blah-blah-blah, I just want to update some fields". It would load the object into Cache and allow you to do the update without doing the SELECT first. There is also an updateOrSave() in Spring, but that actually does the SELECT first.

Debugging LINQ to SQL SubmitChanges()

I am having a really hard time attempting to debug LINQ to SQL and submitting changes.
I have been using http://weblogs.asp.net/scottgu/archive/2007/07/31/linq-to-sql-debug-visualizer.aspx, which works great for debugging simple queries.
I'm working in the DataContext Class for my project with the following snippet from my application:
JobMaster newJobToCreate = new JobMaster();
newJobToCreate.JobID = 9999
newJobToCreate.ProjectID = "New Project";
this.UpdateJobMaster(newJobToCreate);
this.SubmitChanges();
I will catch some very odd exceptions when I run this.SubmitChanges;
Index was outside the bounds of the array.
The stack trace goes places I cannot step into:
at System.Data.Linq.IdentityManager.StandardIdentityManager.MultiKeyManager`3.TryCreateKeyFromValues(Object[] values, MultiKey`2& k)
at System.Data.Linq.IdentityManager.StandardIdentityManager.IdentityCache`2.Find(Object[] keyValues)
at System.Data.Linq.IdentityManager.StandardIdentityManager.Find(MetaType type, Object[] keyValues)
at System.Data.Linq.CommonDataServices.GetCachedObject(MetaType type, Object[] keyValues)
at System.Data.Linq.ChangeProcessor.GetOtherItem(MetaAssociation assoc, Object instance)
at System.Data.Linq.ChangeProcessor.BuildEdgeMaps()
at System.Data.Linq.ChangeProcessor.SubmitChanges(ConflictMode failureMode)
at System.Data.Linq.DataContext.SubmitChanges(ConflictMode failureMode)
at System.Data.Linq.DataContext.SubmitChanges()
at JobTrakDataContext.CreateNewJob(NewJob job, String userName) in D:\JobTrakDataContext.cs:line 1119
Does anyone have any tools or techniques they use? Am I missing something simple?
EDIT:
I've setup .net debugging using Slace's suggestion, however the .net 3.5 code is not yet available: http://referencesource.microsoft.com/netframework.aspx
EDIT2:
I've changed to InsertOnSubmit as per sirrocco's suggestion, still getting the same error.
EDIT3:
I've implemented Sam's suggestions trying to log the SQL generated and to catch the ChangeExceptoinException. These suggestions do not shed any more light, I'm never actually getting to generate SQL when my exception is being thrown.
EDIT4:
I found an answer that works for me below. Its just a theory but it has fixed my current issue.
I always found useful to know exactly what changes are being sent to the DataContext in the SubmitChanges() method.
I use the DataContext.GetChangeSet() method, it returns a ChangeSet object instance that holds 3 read-only IList's of objects which have either been added, modified, or removed.
You can place a breakpoint just before the SubmitChanges method call, and add a Watch (or Quick Watch) containing:
ctx.GetChangeSet();
Where ctx is the current instance of your DataContext, and then you'll be able to track all the changes that will be effective on the SubmitChanges call.
First, thanks everyone for the help, I finally found it.
The solution was to drop the .dbml file from the project, add a blank .dbml file and repopulate it with the tables needed for my project from the 'Server Explorer'.
I noticed a couple of things while I was doing this:
There are a few tables in the system named with two words and a space in between the words, i.e. 'Job Master'. When I was pulling that table back into the .dbml file it would create a table called 'Job_Master', it would replace the space with an underscore.
In the orginal .dbml file one of my developers had gone through the .dbml file and removed all of the underscores, thus 'Job_Master' would become 'JobMaster' in the .dbml file. In code we could then refer to the table in a more, for us, standard naming convention.
My theory is that somewhere, the translation from 'JobMaster' to 'Job Master' while was lost while doing the projection, and I kept coming up with the array out of bounds error.
It is only a theory. If someone can better explain it I would love to have a concrete answer here.
My first debugging action would be to look at the generated SQL:
JobMaster newJobToCreate = new JobMaster();
newJobToCreate.JobID = 9999
newJobToCreate.ProjectID = "New Project";
this.UpdateJobMaster(newJobToCreate);
this.Log = Console.Out; // prints the SQL to the debug console
this.SubmitChanges();
The second would be to capture the ChangeConflictException and have a look at the details of failure.
catch (ChangeConflictException e)
{
Console.WriteLine("Optimistic concurrency error.");
Console.WriteLine(e.Message);
Console.ReadLine();
foreach (ObjectChangeConflict occ in db.ChangeConflicts)
{
MetaTable metatable = db.Mapping.GetTable(occ.Object.GetType());
Customer entityInConflict = (Customer)occ.Object;
Console.WriteLine("Table name: {0}", metatable.TableName);
Console.Write("Customer ID: ");
Console.WriteLine(entityInConflict.CustomerID);
foreach (MemberChangeConflict mcc in occ.MemberConflicts)
{
object currVal = mcc.CurrentValue;
object origVal = mcc.OriginalValue;
object databaseVal = mcc.DatabaseValue;
MemberInfo mi = mcc.Member;
Console.WriteLine("Member: {0}", mi.Name);
Console.WriteLine("current value: {0}", currVal);
Console.WriteLine("original value: {0}", origVal);
Console.WriteLine("database value: {0}", databaseVal);
}
}
}
You can create a partial class for your DataContext and use the Created or what have you partial method to setup the log to the console.out wrapped in an #if DEBUG.. this will help you to see the queries executed while debugging any instance of the datacontext you are using.
I have found this useful while debugging LINQ to SQL exceptions..
partial void OnCreated()
{
#if DEBUG
this.Log = Console.Out;
#endif
}
The error you are referring to above is usually caused by associations pointing in the wrong direction. This happens very easily when manually adding associations to the designer since the association arrows in the L2S designer point backwards when compared to data modelling tools.
It would be nice if they threw a more descriptive exception, and maybe they will in a future version. (Damien / Matt...?)
This is what I did
...
var builder = new StringBuilder();
try
{
context.Log = new StringWriter(builder);
context.MY_TABLE.InsertAllOnSubmit(someData);
context.SubmitChanges();
}
finally
{
Log.InfoFormat("Some meaningful message here... ={0}", builder);
}
A simple solution could be to run a trace on your database and inspect the queries run against it - filtered ofcourse to sort out other applications etc. accessing the database.
That ofcourse only helps once you get past the exceptions...
VS 2008 has the ability to debug though the .NET framework (http://blogs.msdn.com/sburke/archive/2008/01/16/configuring-visual-studio-to-debug-net-framework-source-code.aspx)
This is probably your best bet, you can see what's happening and what all the properties are at the exact point in time
Why do you do UpdateJobMaster on a new instance ? Shouldn't it be InsertOnSubmit ?
JobMaster newJobToCreate = new JobMaster();
newJobToCreate.JobID = 9999
newJobToCreate.ProjectID = "New Project";
this.InsertOnSubmit(newJobToCreate);
this.SubmitChanges();
This almost certainly won't be everyone's root cause, but I encountered this exact same exception in my project - and found that the root cause was that an exception was being thrown during construction of an entity class. Oddly, the true exception is "lost" and instead manifests as an ArgumentOutOfRange exception originating at the iterator of the Linq statement that retrieves the object/s.
If you are receiving this error and you have introduced OnCreated or OnLoaded methods on your POCOs, try stepping through those methods.
Hrm.
Taking a WAG (Wild Ass Guess), it looks to me like LINQ - SQL is trying to find an object with an id that doesn't exist, based somehow on the creation of the JobMaster class. Are there foreign keys related to that table such that LINQ to SQL would attempt to fetch an instance of a class, which may not exist? You seem to be setting the ProjectID of the new object to a string - do you really have an id that's a string? If you're trying to set it to a new project, you'll need to create a new project and get its id.
Lastly, what does UpdateJobMaster do? Could it be doing something such that the above would apply?
We have actually stopped using the Linq to SQL designer for our large projects and this problem is one of the main reasons. We also change a lot of the default values for names, data types and relationships and every once in a while the designer would lose those changes. I never did find an exact reason, and I can't reliably reproduce it.
That, along with the other limitations caused us to drop the designer and design the classes by hand. After we got used to the patterns, it is actually easier than using the designer.
I posted a similar question earlier today here: Strange LINQ Exception (Index out of bounds).
It's a different use case - where this bug happens during a SubmitChanges(), mine happens during a simple query, but it is also an Index out of range error.
Cross posting in this question in case the combination of data in the questions helps a good Samaritan answer either :)
Check that all the "primary key" columns in your dbml actually relate to the primary keys on the database tables. I just had a situation where the designer decided to put an extra PK column in the dbml, which meant LINQ to SQL couldn't find both sides of a foreign key when saving.
I recently encountered the same issue: what I did was
Proce proces = unit.Proces.Single(u => u.ProcesTypeId == (from pt in context.ProcesTypes
where pt.Name == "Fix-O"
select pt).Single().ProcesTypeId &&
u.UnitId == UnitId);
Instead of:
Proce proces = context.Proces.Single(u => u.ProcesTypeId == (from pt in context.ProcesTypes
where pt.Name == "Fix-O"
select pt).Single().ProcesTypeId &&
u.UnitId == UnitId);
Where context was obviously the DataContext object and "unit" an instance of Unit object, a Data Class from a dbml file.
Next, I used the "proce" object to set a property in an instance of another Data Class object. Probably the LINQ engine could not check whether the property I was setting from the "proce" object, was allowed in the INSERT command that was going to have to be created by LINQ to add the other Data Class object to the database.
I had the same non speaking error.
I had a foreign key relation to a column of a table that was not the primary key of the table, but a unique column.
When I changed the unique column to be the primary key of the table the problem went away.
Hope this helps anyone!
Posted my experiences with this exception in an answer to SO# 237415
I ended up on this question when trying to debug my LINQ ChangeConflictException. In the end I realized the problem was that I manually added a property to a table in my DBML file, but I forgot to set the properties like Nullable (should have been true in my case) and Server Data Type
Hope this helps someone.
This is a long time ago, but I had the same problem and the error was because of a trigger with a select statement. Something like
CREATE TRIGGER NAME ON TABLE1 AFTER UPDATE AS SELECT table1.key from table1
inner join inserted on table1.key = inserted.key
When linq-to-sql runs the update command, it also runs a select statement to receive the auto generated values in the same query and expecting the first record set to contains the columns "asked for" but in this case the first row was the columns from the select statement in the trigger. So linq-to-sql was expecting two autogenerated columns, but it only received one column (with wrong data) and that was causing this exception.

Resources