We are using Spring MVC 4.1.2 and Spring Data JPA 1.9.0. Everything works fine but when we have custom query with only selected field for a given entity then our json response does not include property name in the response, instead it just included property value.
If I correctly guess, your custom query looks like:
SELECT e.myProperty FROM Entity e [WHERE ...]
The effect of this is that you get a List<Object[]> containing only the array of property values instead of an object that has a field with the name myProperty and its value is the value in the database.
The solution is to create a custom data-transfer object, which has this one field and assign the value in the constructor
public class MyPropertyDTO { // find a better name, though :)
private int myProperty;
public MyPropertyDTO(int myProperty) {
this.myProperty = myProperty;
}
public int getMyProperty() {
return myProperty;
}
}
Then rewrite your query as:
SELECT NEW com.mycompany.MyPropertyDTO(e.myProperty) FROM Entity e [WHERE ...]
In theory you could even use your original Entity class, add a json view on myProperty and create the matching constructor instead of creating a brand new class.
Related
Here is my Enum:
public enum AdvertStatus
{
Active,
Archived
}
And my entity type:
public record Advertisement
{
...
public AdvertStatus Status { get; set; }
...
}
In database it's stored as int, Database is Postgree
When I try to compare it like so:
data = data.Where(x => x.Status == searchValues.Status);
Entity Framework throws an exception sayng:
.Status == (int)__searchValues_Status_3)' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'.
I tried solutions from this question: LINQ TO ENTITY cannot compare to enumeration types but it did't work.
EDIT 1:
data is database table context IQueryable<AdvertisementDTO>
searchValues.Status is type of AdvertStatus from search filter
The issue may be higher up in your Linq query, such as you are attempting to project with a Select or ProjectTo before filtering. For simple types like int/string this should work, but depending on how your DTO is declared you might be introducing problems for mpgsql.
For instance if your query is something like:
var query = _context.Advertisements
.Select(x => new AdvertisementDTO
{
// populate DTO
}).Where(x => x.Status == searchValues.Status)
// ....
then npgsql may be having issues attempting to resolve the types between what is in the DTO and the enumeration in your searchValues. From what the exception detail looks like, npgsql is trying to be "safe" with the enum and casting to intbut feeding that to PostgreSQL that results in invalid SQL. I did some quick checks and the DTO would need to be using the same Enum type (C# complains if the DTO cast the value to int, cannot use == between AdvertStatus and int fortunately) The project may have something like a value converter or other hook trying to translate enumerations which is getting brought into the mix and gunking up the works.
Try performing the Where conditions prior to projection:
var query = _context.Advertisements
.Where(x => x.Status == searchValues.Status)
.Select(x => new AdvertisementDTO
{
// populate DTO
})
// ....
If the data value is stored as an Int then this should work out of the box. npgsql does support mapping to string (which would require a ValueConverter) as well as database declared enumerations. (https://www.postgresql.org/docs/current/datatype-enum.html) However, Int columns should work fine /w enums.
If that doesn't work, I'd try with a new DbContext instance pointed at the DB and a simple entity with that Enum to load a row from that table to eliminate whether npgsql is translating the enum correctly, just to eliminate any possible converters or other code that the main DbContext/models/DTOs may be contributing.
It was all my mistake in higher repo Select projection.
Thanks you all for help. Cheers.
Assume that I have want to capture a bunch of request parameters as one object like this:
#GetMapping("/")
public List<Item> filterItems(#Valid Filter filter){}
and the Filter class looks like this:
class Filter {
public String status;
public String start;
public String end;
}
Now in the API the request parameter name is state instead of status like this ?state=A&start=1&end=2. How do I make these request parameters to map to my Filter object without having to rename status? I know if I have #RequestParam("state") String status it would work but I want it to be part of the request object.
I tried adding #JsonProperty('state') on the field but it didn't work.
I am storing a hash-map in a riak bucket like this:
bucket.store(key, docHashMap).execute();
I would like to store the object with a secondary index.
How would I accomplish this? I am aware that the IRiakObject has a addIndex method, but how do I access the IRiakObject before it is stored?
I would think that what I am trying to do is the expected use-case, yet I am not able to find any documentation or examples on this. If you can point me to one that would be greatly appreciated.
Thanks!
Update:
#Brian Roach answered this on the Riak mailing list and below. Here is the custom class that I wrote that extends the HashMap:
class DocMap extends HashMap<String, Object> {
/**
* Generated id
*/
private static final long serialVersionUID = 5807773481499313384L;
#RiakIndex(name="status") private String status;
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}
I can still use the object as an ordinary hashmap and store keys and values, but it will also write "status" to a secondary index (and actually end up being called "status_bin" since it's a string.
If you're just passing in an instance of the core Java HashMap ... you can't.
The way the default JSONConverter works for metadata (such as indexes)
is via annotations.
The object being passed in needs to have a field annotated with
#RiakIndex("index_name"). That field can be a Long/Set<Long> or
String/Set<String> (for _int and _bin indexes respectively).
These are not converted to JSON so they won't affect your serialized
data. You can have multiple fields for multiple indexes.
You don't have to append "_int" or "_bin" to the index name in the
annotation - it's done automatically based on the type.
Easiest thing to do woud be to extend HashMap and simply add the
annotated field(s).
I am developing a web application where in i have a WCF service which interacts with the database using entity framework. I want to get rid of creating Classes for each & every LINQ query
e.g
public class Emp
{
public int CD{get;set;}
public string Name{get;set;}
}
public List<Emp> GetServTypeForPromotionDue()
{
return (from a in Context.TableName
select new Emp{ a.CD, a.NAME });
}
for other table & LINQ i have to create a separate class every time. Alternative to this is to use Anonymous method which is not preferable solution. To avoid both the methods I am using Tuple Class where I return List> or List> depending on the return type. This works fine but the problem is I am binding the result of LINQ query directly to a Gridview By default Tuple has properties item1,item2,..& so on. So my griview shows these names are column names so, Is there any way I can change the property name to CD, Name instead of Tuple's Item1, Item2 before binding to grid?
when binding the list, you could use linq:
this.grid.DataSource = tupleList.Select(i => new
{
FirstName = i.Item1,
LastName = i.Item2,
CD = i.Item3
});
You would have to change the column names on the GridView and not the tuple. A tuple is a lightweight type that doesn't support much customization (MSDN). If you know what you are binding to the GridView, change the column names by handling the RowDataBound event and checking the RowType of Header, then changing the column names there.
I'm a beginner with MyBatis.
I just want to know how to insert a collection of objects from an instance of a class. Say I have a class User related to a Note in one-to-many relationship. I just like to mention that I built my schema using JPA 2 annotations via Hibernate's hbm2ddl. I'll add the key JPA annotations I used in the sample code below.
Here's a sample:
#Entity
public class User {
...
#OneToMany
#JoinColumn(name="user")
public List<Note> getNotes() {...}
...
}
Now, everytime I insert something into User table I have to insert instances into the Note table if the list is not empty. Take note of the #JoinColumn in Note table which should have the id of the inserted User, which I have set to be autogenerated.
Has anyone got something like this working? Thanks.
When using a regular MyBatis XML mapping config you can use something like this:
Java classes:
class EnclosingType {
private List<ElementType> elements;
}
class ElementType {
String a;
String b;
(...)
}
Mapper xml:
<mapper
namespace="my.example.ElementType">
<insert id="insertElements" parameterType="EnlosingType">
INSERT INTO ELEMENTTYPE (enclosingTypeId, column_a, column_b)
VALUES
<foreach item="element" index="index" collection="elements"
open="(" separator="),(" close=")">
#{id}, #{element.a}, #{element.b}
</foreach>
</insert>
</mapper>