Hi I'm new to myBatis.
I'm using MyBatis and Spring with mybatis-spring.
How can I pass two different types of objects as parameters, and how can I use their properties in query?
<update id="update" parameterType="A, B"> <!-- ##? -->
UPDATE SOME WHERE x=A.x AND y=B.y <!-- ##? -->
</update>
Do not specify parameterType but use #Param annotation on parameters in mapper:
#Mapper
public interface MyMapper {
void update(#Param("a") A a, #Param("b") B b);
...
}
Then reference them in mapping:
<update id="update" >
UPDATE SOME WHERE x=#{a.x} AND y=#{b.y}
</update>
Use parameterType="map" and #Param annotation.
Method declared in interface:
void mapCategoryAndPage(#Param("categoryLocalId") Long categoryLocalId, #Param("pageLocalId") Long localId);
It is not required that value of #Param annotation must be equal to name of parameter
<insert id="mapCategoryAndPage" parameterType="map">
INSERT INTO
category_page_mapping (
page_local_id,
category_local_id)
VALUES
(#{pageLocalId},
#{categoryLocalId});
</insert>
I would suggest reading the MyBatis documentation - it is pretty comprehensive and accurate.
Lets take an example: updating a customer's name from a com.mycompany.Customer POJO instance, which has a getFirstName() getter.
Pass an instance of your Customer class as the parameter
Set the parameterType= "com.mycompany.Customer". But check out the alias facility - then you can use the shorthand version parameterType="Customer"
Use the standard MyBatis syntax in the SQL: ... set FIRST_NAME = #{firstName}
(Edit) If you need to pass multiple objects there are various options:
Pass a map containing the multiple objects
Create a utility class the aggregates your multiple classes, and pass this as the parameter.
Again, please read the manual...
Related
I have a Spring Boot app that is modeling ActityStreams objects and for the most part Jackson's Polymorphic Deserialization works well.
There are 'objects' in the JSON which are references (links) and not JSON objects with type information. For instance
"actor":"https://some.actors.href/ rather than
"actor":{
"type":"Actor",
"name":"SomeActor"
}
I've written custom deserializers and and placed them on the fields to deal with this
#JsonDeserialize (using = ActorOrLinkDeserializer.class)
private Actor actor;
However my ActorOrLinkDeserializer is instantiated but never called and Jackson complains with Missing type id when trying to resolve subtype of [simple type, class org.w3.activity.streams.Actor]: missing type id property 'type' (for POJO property 'actor') which is from the polymorphic deserializer.
It appears that the polymorphic deserialization code takes precedence over my local #JsonDeserialize annotation and I need a way to force my code to run first.
I've tried using my own ObjectMapper rather than Boot's and there's no difference.
I'd appreciate pointers and suggestions.
It turns-out there's a fairly simple solution to this problem using a DeserializationProblemHandler.
What I've implemented that works for all test cases so far is
1.
objectMapper.addHandler(new DeserProblemHandler());
or register with Spring Boot.
2.
public class DeserProblemHandler extends DeserializationProblemHandler {
public JavaType handleMissingTypeId(DeserializationContext ctxt, JavaType baseType, TypeIdResolver idResolver, String failureMsg) {
return TypeFactory.defaultInstance().constructType(baseType.getRawClass());
}
}
Add a constructor to each of the polymorphic classes that takes a string argument which is the href.
I am using Dozer mapper in Spring boot. If I map Data from Entity to EntityDTO, then work of dozer maper is to copy the data from entity class to EntityDTO and it does the same in case of primitives. But suppose I have a class like this
Class Entity{
public EntityChild entityChild; //leaving getter and setter here.
}
and DTO with name EntityDTO
Class EntityDTO{
public EntityChildDTO entityChildDTOs; //leaving getter and setter here.
}
then it doesn't map the data from entityChild to entityChildDTOs, Can anyone please help me how to resolve this issue ?
The attribute names have to be the same for Dozer to automatically map it. So EntityDTO's attribute has to be named entityChild too, for example.
Part of mapping for this two entities, based on the official manual:
<mapping>
<class-a>Entity</class-a>
<class-b>EntityDTO</class-b>
<field>
<!-- this is the same for all sub classes -->
<a>entityChild</a>
<b>entityChildDTOs</b>
</field>
</mapping>
<!--Add mapping for EntityChild and EntityChildDTO here-->
You task is very basic and it definitely works in Dozer.
There are a lot of examples online of using QueryDSL like this:
public class CustomerRepositoryImpl
extends QueryDslRepositorySupport
implements CustomerRepositoryCustom {
public Iterable<Customer> findAllLongtermCustomersWithBirthday() {
QCustomer customer = QCustomer.customer;
return from(customer)
.where(hasBirthday().and(isLongTermCustomer()))
.list(customer);
}
}
This code makes sense, but I am wondering why customer is "duplicated" in the method call to list().
Shouldn't the type be obvious from the reference in from(customer)?
from defines the source and list the projection. Querydsl query classes don't have any generic type argument for the return type, the projection (select part) is defined in the last part of the query construction chain.
Examples for cases where a different projection than the source is wanted
specific columns only: query.list(customer.firstName, customer.lastName)
constructor invocation : Projections.constructor(...)
Bean population: Projections.bean(...)
multiple from calls are used
any public method, any return type, partial class name match, any method, taking session as the first arg.
I came up with #Before(value="execution(public * *ServiceImpl.*(*.PlayerSession,..))")
this doesn't work. but when I change it to #Before(value="execution(public * com.mycompany.mypkg.IdServiceImpl.*(*.PlayerSession,..))") it works. can I get an explanation for this.
Try to use this instead:
#Before(value = "execution(public * *..*ServiceImpl.*(*..PlayerSession, ..))")
you need to add *.. so that spring would search for your *ServiceImpl service in any package
note: just for convenience I have added it also before your PlayerSession object
I know I can validate forms in Spring, but can I apply similar validate to URL parameters? For example, I have a method in my controller as follows:
public String edit(#PathVariable("system") String system,
#RequestParam(value="group") String group,
ModelMap model) throws DAOException {
Can I validate the values of system and group before the method is called, to ensure they are of a certain value or match a certain regex?
Thanks
You may be able to use Spring Asserts for this. The Assert api (http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/util/Assert.html) runs a supplied expression against the specified parameters and if the expression equates to false then it throws an exception.
Ex:
Assert.isTrue(system.equals("ValidSystemName"), "You must supply a valid system");
It also contains functions to check that parameters are not null or are not empty strings, etc.
Create an annotation that marks parameters that should be validated. This annotation needs a #Retention of RUNTIME and a #Target of ElementType.PARAMETER.
Create a validator implemented as an AspectJ Aspect.
Wrap calls to controllers with this validator.
A sample annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.PARAMETER)
#Documented
public #interface ValidSystemParameter {
}
A sample validator:
#Aspect
public class ValidSystemParameterValidator {
#Pointcut("TODO: write your pointcut expression")
public void controllerMethodWithValidSystemParameter();
#Before(pointcut = "controllerMethodWithValidSystemParameter()")
public void validateSystemParameter(String systemParameter) {
// validate the parameter (throwing an exception)
}
}
To learn about the AspectJ pointcut expression language see: http://www.eclipse.org/aspectj/doc/released/progguide/language-joinPoints.html
To learn about AspectJ integration in Spring see: http://static.springsource.org/spring/docs/current/spring-framework-reference/html/aop.html#aop-ataspectj
I might be a little late, but with Spring 3.0 you have the option of using JSR-303 validation with the #Valid annotation. There are also some more specific annotations as #DateTimeFormat and #NumberFormat. More details here: http://static.springsource.org/spring/docs/3.0.5.RELEASE/reference/validation.html#validation-mvc
As I see it you have two options:
Define your request parameters as objects and user JSR-303
validation.
Use the Assert api as mentioned above.
If you just want to make a simple validation on a single value, I would go with the latter (that's what I did when I had simple int values to check for max value).