Let's say I have an object that's being passed from some UI to my graphQL
class Person{
String name;
String age;
String address;
}
This is a preexisting user, and I was sent the name and the address, but not the age. Can I tell JPA "Hey, if you see a NULL field, please do not overwrite it, just ignore it and update the other fields"
#GraphQLMutation(name = "createPerson")
public List<Person> createPeople(#GraphQLArgument(name = "people") List<Person> people) {
return personDao.saveAll(people);
}
#Repository
public interface StrategyDAO extends JpaRepository<Strategy, Integer>{
#PleaseDontOverWriteNulls
void saveAll(List<Person>)
}
The annotation in my repository is representative of what would be great to have but which I haven't been able to find.
I have a Spring Boot app that has basic CRUD services. For the read services I want to see their relations as well. There is no problem for implementing relations by #ManyToOne, #OneToOne, etc. annotations like this example.
My problem is I want to enable this relations based on a parameter in list service or I could use another endpoint as well. How can I achieve this? Any suggestions are welcome.
parameter version could be like ->
/employe/list?includeRelations=true
endpoint version could be like ->
/employee/list/byRelations
My entities are like;
#Entity
#Table(name = "employee")
public class Employee{
private long id;
private String name;
private Address address;
// getter setters
}
#Entity
#Table(name = "address")
public class Address {
private long id;
private String name;
private String postalCode;
// getter setters
}
EDIT
e.g.
without includeRelations=true '/employee/list' service should return this;
{
"id": 1,
"name": "Jane"
}
with includeRelations=true '/employee/list' service should return this;
{
"id": 1,
"name": "Jane"
"address": {
"id":1,
"name": "HOME",
"postalCode": "11111"
}
}
its some sudo code for your understanding . you can use Query Parameter and In Condition you call repo what you want :
for my scenario i want different response short, medium and long
#RequestMapping(value = "/getContacts", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE, headers = "Accept=application/json")
public String getContact(#RequestBody ContactItemRequestInfo contactItemRequestInfo,
#RequestParam(required = false) String key,
String Contact)
{
if(key.equals("medium"))
{
return Contact="{\"responseCode\":\"02\",\"responseDescription\":\"Success\",\"totalCount\":2,\"contacts\":[{\"id\":114,\"firstName\":\"ali\",\"lastName\":\"kamran\"},{\"id\":115,\"firstName\":\"usman\",\"lastName\":\"khan\",\"middleName\":\"saad\"}]}";
}
else if(key.equals("long"))
{
return Contact="{\"responseCode\":\"03\",\"responseDescription\":\"Success\",\"totalCount\":2,\"contacts\":[{\"id\":114,\"firstName\":\"ali\",\"lastName\":\"kamran\"},{\"id\":115,\"firstName\":\"usman\",\"lastName\":\"khan\",\"middleName\":\"saad\"}]}";
}
else
{
return Contact="{\"responseCode\":\"00\",\"responseDescription\":\"Success\",\"totalCount\":2,\"contacts\":[{\"id\":114,\"firstName\":\"ali\",\"lastName\":\"kamran\"},{\"id\":115,\"firstName\":\"usman\",\"lastName\":\"khan\",\"middleName\":\"saad\"}]}";
}
}
It will be helpful for you !!
One of the ways would be to have different data transfer objects to return, depending on the REST request.
Let's assume you have the following classes, apart from entities.
class EmployeeDto {
private Long id;
private String name;
}
class EmployeeAddressDto {
private Long id;
private String name;
private AddressDto address;
}
class AddressDto {
private Long id;
private String name;
private int postalCode;
}
Then in a controller you would do something like this.
#GetMapping("/employee/list")
public ResponseEntity<?> getEmployees(#RequestParam int detailed) {
if (detailed) {
return employeeService.getDetailedEmployeeList();
} else {
return employeeService.getEmployeeList();
}
}
Service inteface would look like this.
interface EmployeService() {
List<EmployeeDto> getEmployeeList();
List<EmployeeAddressDto> getDetailedEmployeeList();
}
You would also need to handle entities to transfer objects conversions.
You can annotate the relations with fetchType=Lazy . Then invoke the getters to manually load the needed relations.
Another option is to eagerly load all relationships, but annotate the response with #JsonView and exclude the relations you don't need.
I have the following MongoDB Repository
public interface TeamRepository extends MongoRepository<Team, TeamId> {
....
}
And the following classes:
public abstract class DbId implements Serializable {
#Id
private final String id;
public DbId(final String id) { this.id = id;}
public String getId() { return id;}
}
public class TeamId extends DbId {
public TeamId(final String id) {
super(id)
}
}
As you can see, I have like a custom id for the repository (I have MongoRepository instead of something like MongoRepository). But, when I am trying to save a Team object, I get an error saying that MongoDB does not know how to generate DBId. Any clue?
MongoDb (or any database) would not know how to generate a string ID without you informing it what the value of the string is.
The default #Id is a string representation of ObjectId, which can be auto-generated by MongoDB. If you are changing the type of string ObjectId to a class, then at least the class needs to define:
** Conversion to string (serialisable), for example:
#Override
public String toString() {
return String.format(
"TeamID[uniqueString=%s]",
myUniqueString);
}
** How to generate the Id.
You can define a method in your TeamRepository i.e. save() to specify how your string can be generated. Alternatively you can check out
https://www.mkyong.com/mongodb/spring-data-mongodb-auto-sequence-id-example/
Where the example specify getNextSequenceId() to generate NumberLong custom id. Hopefully that guides you to your answer.
I have this enum :
public enum DocumentTypes {
PDF("PDF Document"), JPG("Image files (JPG)"), DOC("Microsoft Word documents");
private final String displayName;
DocumentTypes(final String display) {
this.displayName = display;
}
#Override
public String toString() {
return this.displayName;
}
}
And a model like this :
#Entity
#Table(name = "documents")
public class Document extends Model {
#Id
public Long id;
#Constraints.Required
#Formats.NonEmpty
#Enumerated(EnumType.STRING)
#Column(length=20, nullable=false)
public DocumentTypes type;
#Constraints.Required
#Formats.NonEmpty
#Column(nullable=false)
public String document;
}
I match the enum using this in my controller :
DynamicForm form = form().bindFromRequest();
// ...
Document doc = new Document();
doc.type = DocumentTypes.valueOf(form.field("type").value());
doc.save();
The problem is that in database, it's stored as "Microsoft Word documents", but I would prefer to store it as DOC.
How can I do that?
You can define it very fine granular with the Anotation EnumMapping or EnumValue. This works with the old version org.avaje.ebean.
It seems that there was a complete rewrite of the code. In the actual version there is a different approach.
I am trying to use AutoMapper for the first time and have some problems with it.
My code is below and I get error below. Maybe someone could show how to map the list of models?
cannot convert from 'System.Linq.IQueryable<AnonymousType#1>' to 'Entity.Product' C:\Users\Administrator\Projects\PC\trunk\PC\Controllers\AdminController.cs 37 100 PC
public class ProductViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public int UsersCount { get; set; }
}
var products = _repository.GetProducts(true).Select(p=> new
{
p.Id,
p.Name,
UsersCount = 0
});
Mapper.CreateMap<Product, ProductViewModel>();
ViewData["Products"] = Mapper.Map<IEnumerable<Product>, IEnumerable<ProductViewModel>>(products); //Error appears on products object
//Product domain model(linq2sql generated model)
public partial class Product : INotifyPropertyChanging, INotifyPropertyChanged
{
private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty);
private int _Id;
private bool _Active;
private System.Nullable<int> _Sort;
private System.Nullable<int> _Category;
private string _Name;
private int _ProductTypeId;
private decimal _Price;
private System.Nullable<int> _Months;
private System.Nullable<int> _Credits;
private string _Features;
private string _BlockReason;
private string _BuyUrl1;
private string _BuyUrl2;
private bool _UsersManager;
}
In your LINQ query you select an anonymous object. Make sure you select a Product which is your source type (or more specifically IEnumerable<Product>):
IEnumerable<Product> products = _repository.GetProducts(true);
IEnumerable<ProductViewModel> productsViewModel = Mapper.Map<IEnumerable<Product>, IEnumerable<ProductViewModel>>(products);
return View(productsViewModel);
Also do not call Mapper.CreateMap<TSource, TDest> inside your controller action. This must be called only once in the lifetime of the AppDomain, ideally in your Application_Start.
Also notice that I have gotten rid of ViewData which is a great thing. You don't need ViewData. You are working with view models. That's what they are supposed to do. Contain information that will be needed by your view in a strongly typed manner.