How to handle jpa entity - spring

I have a table client and from retrieving results I use this way
public ClientParent getClient(Long clientId,Long parentId){
String queryString="SELECT cp FROM Client cp where cp.cid.id=:clientId " +
"and cp.pid.id=:parentId ";
Query query=entityManagerUtil.getQuery(queryString);
query.setParameter("clientId", clientId);
query.setParameter("parentId", parentId);
return (ClientParent)query.getSingleResult();
}
This is the DAO method.
Actually for getting client at 1st control goes to controller class then to service and then DAO class
Now lets say that the client table is empty so in this case return (ClientParent)query.getSingleResult(); will throw me error.
I can handle this in by wrting in try catch block in service class as well as in controller class.But wanted to know if I can do with out throwing any exception.I mean do I have change the query or what should I return so that it will never throw exception even if the table is empty

you can use the getResultList() method
public ClientParent getClient(Long clientId,Long parentId){
String queryString="SELECT cp FROM Client cp where cp.cid.id=:clientId " +
"and cp.pid.id=:parentId ";
Query query=entityManagerUtil.getQuery(queryString);
query.setParameter("clientId", clientId);
query.setParameter("parentId", parentId);
List<ClientParent> result = query.getResultList();
if (result != null && result.size() >0){
return result.get(0);
} else {
return null;
}
}

I suggest you to surround your code with try-catch block. So will sure that the data is correct.
try {
// ... your code goes here
// getSingleResult()
return XXX;
} catch(NonUniqueResultException e) {
// here you know there is some bad data
// so you can ignore it or do something
} catch(NoResultException e){
return null;
}

Related

Spring Webflux - R2dbc : How to run a child query and update value while iterating a result set

I am new to Reactive repositories and webflux. I am fetching a list of data from DB, iterating it using map() to build a DTO class object, in this process I need to run another query to get the count value and update the same DTO object. When I try as follows, the count is set to null
#Repository
public class CandidateGroupCustomRepo {
public Flux<CandidateGroupListDTO> getList(BigInteger userId){
final String sql = "SELECT gp.CANDIDATE_GROUP_ID,gp.NAME ,gp.GROUP_TYPE \n" +
" ,gp.CREATED_DATE ,cd.DESCRIPTION STATUS ,COUNT(con.CANDIDATE_GROUP_ID)\n" +
" FROM ........" +
" WHERE gp.CREATED_BY_USER_ID = :userId GROUP BY gp.CANDIDATE_GROUP_ID,gp.NAME ,gp.GROUP_TYPE \n" +
" ,gp.CREATED_DATE ,cd.DESCRIPTION";
return dbClient.execute(sql)
.bind("userId", userId)
.map(row ->{
CandidateGroupListDTO info = new CandidateGroupListDTO();
info.setGroupId(row.get(0, BigInteger.class));
info.setGroupName(row.get(1, String.class)) ;
info.setGroupType(row.get(2, String.class));
info.setCreatedDate( row.get(3, LocalDateTime.class));
info.setStatus(row.get(4, String.class));
if(info.getGroupType().equalsIgnoreCase("static")){
info.setContactsCount(row.get(5, BigInteger.class));
}else{
getGroupContactCount(info.getGroupId()).subscribe(count ->{
System.out.println(">>>>>"+count);
info.setContactsCount(count);
});
}
return info;
}
)
.all() ;
}
Mono<BigInteger> getGroupContactCount(BigInteger groupId){
final String sql = "SELECT 3 WHERE :groupId IS NOT NULL;";
return dbClient.execute(sql)
.bind("groupId", groupId)
.map(row -> {
System.out.println(row.get(0, BigInteger.class));
return row.get(0, BigInteger.class);
} ).one();
}
}
When I call getGroupContactCount, I am trying to extract count from Mono<BigInteger> and set it in my DTO.... sys out prints the count value correctly but still I get null for count in response.
You are calling subscribe in the middle which in turn is essentially blocking. The one subscribing is usually the final consumer, which im guessing your spring application is not, most likely the final consumer is the webpage that initiated the call. Your server is the producer.
call the database, flatMap and return.
return dbClient.execute(sql)
.bind("userId", userId)
.flatMap(row ->{
CandidateGroupListDTO info = new CandidateGroupListDTO();
info.setGroupId(row.get(0, BigInteger.class));
info.setGroupName(row.get(1, String.class)) ;
info.setGroupType(row.get(2, String.class));
info.setCreatedDate( row.get(3, LocalDateTime.class));
info.setStatus(row.get(4, String.class));
if(info.getGroupType().equalsIgnoreCase("static")){
return Mono.just(info.setContactsCount(row.get(5, BigInteger.class)));
} else {
return getGroupContactCount(info.getGroupId()).flatMap(count -> {
info.setContactsCount(count);
return Mono.just(info)
});
}
}).all();
Use map if order matters, otherwise try to use flatMap to do async work.

spring boot + hibernate Can I use entityMnager.persist(item) after I get the item with named query?

I am using spring boot and hibernate. I have a named query where I select an item. Then I want to set some property and then to make entityManager.persist() or entityManager.merge(). Can I do this or the instance of my item will be unmanaged after the named query and persist/merge will fail ?
Here is my code where em.persist() actually do not work:
public String getSMSText(String sourceUrl) {
Rss rss;
List urls = em.createNamedQuery("Rss.getFeedByUrl").setParameter("url", sourceUrl).getResultList();
if (urls.size() != 0) {
rss = (Rss) urls.get(urls.size() - 1);
for (Rss.Item item : rss.getChannel().getItems()) {
try {
if (Utils.isToday(item.getPubDateAsDate()) && !item.isPushed()) {
item.setPushed(true);
em.refresh(item);
em.persist(item);
return item.getTitle() + "." + item.getSummary();
}
} catch (ParseException e) {
logger.info("Cannot parse pub date", e);
}
}
logger.info(sourceUrl + " No news for today!");
return null;
}
return null;
}
My guess is that your change on the item will not have any effect.
You should change your item only when the query transaction is completely closed.
I think you have two way:
1- Change your code to update your entity only when you are sure that the select query transaction was closed.
2- Use EntityManager.refresh() on your item, after the named query and before change and persist it.

Unable to cast object of type CRM 2013 Plugin

I have a Synchronous plugin that runs when any opportunity create/delete/update. And in Plugin if any error comes i have made a function which insert log into database.
In table one field if EntityId, so i am writing the following code :
foreach (PropertyBagEntry entry in (IEnumerable<PropertyBagEntry>)context.InputParameters.Values)
{
DynamicEntity entity = (DynamicEntity)entry.Value;
foreach (Property property in (IEnumerable<Property>)entity.Properties)
{
if (property.GetType().Name == "KeyProperty")
{
str4 = ((Key)entity.Properties[property.Name]).Value.ToString();
break;
}
}
}
In str4 i am getting EntityId of current process.
But it gives one exception very frequently :
Unhandled Exception: System.InvalidCastException: Unable to cast object of type
'ValueCollection[System.String,System.Object]'
to type 'System.Collections.Generic.IEnumerable`1[Microsoft.Crm.Sdk.PropertyBagEntry]'
And i have identified that the following line is giving error
foreach (PropertyBagEntry entry in (IEnumerable)context.InputParameters.Values)
Anyone have idea to convert this line in another way ?
My understanding is that you want to get the GUID of current record, if this is the case then you can do it as:
public void Execute(IServiceProvider serviceProvider)
{
IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
try
{
if (context.MessageName == "Create" || context.MessageName == "Update")
{
if (context.InputParameters.Contains("Target") && (context.InputParameters["Target"] is Entity))
{
Entity currentEntity = (Entity) context.InputParameters["Target"];
Guid currentRecordGuid = currentEntity.Id;
}
}
}
catch (Exception ex)
{
}
}
I believe the type of that collection varies from one message to another. If you are looking to get the Id of the record within a plugin, this helper function may come in handy:
public static Guid GetEntityIdFromContext(IPluginExecutionContext context)
{
string messageName = context.MessageName;
if (context.PrimaryEntityId != Guid.Empty)
{
return context.PrimaryEntityId;
}
else if (messageName == "Create")
{
return new Guid(context.OutputParameters["id"].ToString());
}
else
{
return context.PrimaryEntityId;
}
}
If that doesn't help, would you mind providing the message that causes the error?
If
Unhandled Exception: System.InvalidCastException: Unable to cast
object of type 'ValueCollection[System.String,System.Object]' to type
'System.Collections.Generic.IEnumerable`1[Microsoft.Crm.Sdk.PropertyBagEntry]'
is truly your error, than your issue is not with line
foreach (Property property in (IEnumerable<Property>)entity.Properties)
but with line:
foreach (PropertyBagEntry entry in (IEnumerable<PropertyBagEntry>)context.InputParameters.Values)
The type of context.InputParameters.Values is not castable to an IEnumerable

Why isn't my Where working as I think it should?

I'm trying to get some data from a database whose results can be more than one row.
I've the following code for that:
public System.Linq.IQueryable<Users> getUser2(string idUser)
{
try
{
using (Entities c = new Entities())
{
c.ContextOptions.LazyLoadingEnabled = false;
c.ContextOptions.ProxyCreationEnabled = false;
return c.Users.Include("Empresas").Where(x => x.Login == idUser && x.Empresas.Activa == true);
}
}
catch (Exception ex)
{
throw ex;
}
}
But it doesn't seem to get any result, it shows something like a badly formed Iqueryable, I mean if I expand its results view I can see a message that says "ObjectContext instance has been eliminated and cannot be used for operations that need a connection" If I try to access any Users element with the function ElementAt(index) I get an IndexOutOfBounds error as it looks like it has no data if watched on debug mode.
I've deduced that it's Where fault because this code Works fine in returning the first user it finds that fulfills the condition:
public Users getUser(string idUser)
{
try
{
using (Entities c = new Entities())
{
c.ContextOptions.LazyLoadingEnabled = false;
c.ContextOptions.ProxyCreationEnabled = false;
return c.Users.Include("Empresas").FirstOrDefault(x => x.Login == idUser && x.Empresas.Activa == true);
}
}
catch (Exception ex)
{
throw ex;
}
}
Does that Where work differently than what I think I should? If then, how could I get several data that fulfills the conditions I'm passing the same as in getUser but for several rows?
Thanks for your attention.
You need to enumerate the result, so after the "where" statement add. ToList() which will enumerate and execute the query against your database. FirstOrDefault is executing the query thats why you get a result.
You need to check the deferred methods and understand how they work.
EDIT
The following are some links to show you the deference between the Deferred method vs Immediate methods in LINQ
1- http://www.dotnetcurry.com/showarticle.aspx?ID=750
2- http://www.codeproject.com/Articles/627081/LINQ-Deferred-Execution-Lazy-Evaluation
3- http://visualcsharptutorials.com/linq/deferred-execution
Hope that helps.

Jersey Obfuscating Collections in JSON Output

In my code I can see I am returning a valid Object. This object happens to contain a collection of 'user comments'. This collection is valid and filled with entries right before I return the Response object through JAX-RS. However, when the GET request is completed that collection is mysteriously replaced by a boolean value denoting if the collection is empty or not.
Just to reiterate. Valid, non-empty collection, returned in a GET request as a boolean with field 'empty'
What gives? I know there must be some magic under the hood, but it has been escaping me.
#GET
#Path("{issue: \\w+-\\d+}")
#Produces(MediaType.APPLICATION_JSON)
public Response getIssue(#PathParam("issue") String issue) {
Issue returnedIssue = null;
try {
returnedIssue = jiraService.getIssue(issue);
}
catch (RestClientException ex) {
log.error("ERROR: Could not find issue " + issue + ": " + ex.getMessage());
throwErrorResponse(Response.Status.NOT_FOUND);
}
return getResponse(Response.Status.OK, returnedIssue);
}
This is my POJO: http://docs.atlassian.com/jira-rest-java-client/1.0/apidocs/com/atlassian/jira/rest/client/domain/Issue.html

Resources