-
Notifications
You must be signed in to change notification settings - Fork 12.9k
When insert a list or array,resolve the useGeneratedKeys error. #324
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
I use now mybatis 3.3.0 and get the error - Parameter not found (http://stackoverflow.com/questions/28453475/mybatis-getting-id-from-inserted-array-of-object-returns-error) I've read code from master branch but I don't see there your patches. Can you say 1)was you code accepted by mybatis developers and if yes why there is no you code 2)can I use you patch for version 3.3.0 to solve my problem? |
@PashaTurok You can see the code here: this Issue Code: https://github.com/mybatis/mybatis-3/pull/324/files Source code:Jdbc3KeyGenerator In class At line 45: List<Object> parameters = new ArrayList<Object>();
parameters.add(parameter);
processBatch(ms, stmt, parameters); Create a new List,and only add one value In for (Object parameter : parameters) { the parameters has only on one Object. Judging from the design, it can support insert List and write-back id. I don't know why not merge this request. If you need to, you can refer to this class Jdbc3KeyGenerator - support insert List and write-back id If you use it,in the following code: public void createCore(@Param("cores")List<Object> cores); you need remove |
@emacarron We can discuss this issue. How to solve the problem of insert |
@pagehelper Thank you very much!!! Your solution really solved my problem! Can this be applied for different databases? I mean mysq,db2,ms,oracle? |
@pagehelper One more question - you say "you need remove @param then is will be the default key "list",or you can use key "keys" to replace the "cores"' - this is rule, as I understand for all inserts. Ok, it's not problem. But should I follow this rule and for update? |
@pagehelper: |
@PashaTurok When you use the In MyBatis document:
Full document:http://mybatis.github.io/mybatis-3/sqlmap-xml.html |
@Condor70 Here is an example.You can refer to it. A simple table,named country: CREATE TABLE `country` (
`Id` int(11) NOT NULL AUTO_INCREMENT,
`countryname` varchar(255) DEFAULT NULL,
`countrycode` varchar(255) DEFAULT NULL,
PRIMARY KEY (`Id`)
) ENGINE=InnoDB AUTO_INCREMENT=184 DEFAULT CHARSET=utf8; Mapper.xml: <insert id="insertList" useGeneratedKeys="true" keyProperty="id">
INSERT INTO country (countryname,countrycode )
VALUES
<foreach collection="list" item="item" separator=",">
(#{item.countryname},#{item.countrycode})
</foreach>
</insert> Note: A List<Country> countries = new ArrayList<Country>();
Country country = new Country();
country.setCountryname("cn1");
country.setCountrycode("cc1");
countries.add(country);
Country country2 = new Country();
country2.setCountryname("cn2");
country2.setCountrycode("cc2");
countries.add(country2);
Country country3 = new Country();
country3.setCountryname("cn3");
country3.setCountrycode("cc3");
countries.add(country3); I use three ways to test Insert. use List: int result = sqlSession.insert("insertList", countries);
Assert.assertEquals(3, result);
for (Country c : countries) {
Assert.assertNotNull(c.getId());
} use Map: Map<String, Object> map = new HashMap<String, Object>();
map.put("list",countries);
int result = sqlSession.insert("insertList", map);
Assert.assertEquals(3, result);
for (Country c : countries) {
Assert.assertNotNull(c.getId());
} use Array: first modify the Mapper.xml,change int result = sqlSession.insert("insertList", countries.toArray());
Assert.assertEquals(3, result);
for (Country c : countries) {
Assert.assertNotNull(c.getId());
} Others When use mapper interface,still no problems. |
I fully understand your suggested solution. My problem is that you are required to name your collection "list" or "array" if you are using a parameter map. This seems arbitrary to me. I would prefer it if the name of the collection or array would be derived from the keyProperty. e.g. You could use keyProperty="myObject.children.id" and MyBatis would analyse parameters.myObject.children and decide whether it is a collection, array or plain object before assigning the id(s). |
@Condor70 It's a good idea. I think we can combine the two methods.
private Collection<Object> getParameters(Object parameter) {
Collection<Object> parameters = null;
if (parameter instanceof Collection) {
parameters = (Collection) parameter;
} else if (parameter instanceof Map) {
Map parameterMap = (Map) parameter;
//TODO get key from the keyProperty
//else
//Default key
if (parameterMap.containsKey("list")) {
parameters = (Collection) parameterMap.get("list");
} else if (parameterMap.containsKey("array")) {
parameters = Arrays.asList((Object[])parameterMap.get("array"));
}
}
if (parameters == null) {
parameters = new ArrayList<Object>();
parameters.add(parameter);
}
return parameters;
} |
I create a new pull request:#350 |
with Mapper.java declared like:
But, there's still a question, when mapper interface has more than two parameters, set the auto increment key failed, any one has solution? |
I'm sorry, but Assert.assertNotNull(c.getId()); is not correct, it will return 0 result on getId(), try to check getId() > 0, because by default id in db is more than zero |
Did this fix not make it into 3.3.0? Any idea when this will be available in a release? Or is there a way to override the KeyGenerator and use a custom one? I couldn't find anything about this in the docs. |
We are planning a bug fix release for the 3.3.x branch and we can include 2016-02-03 16:47 GMT+01:00 Brian Pontarelli notifications@github.com:
|
I updated to latest version 3.4.0, but this problem still be reproduced with mysql.
|
After debugging into source code, I found several problems:
it cannot fall to any cases("collection", "list", or "array"), it just an objet. It leads to fail of this fix. After remove Anyone can explain this? |
@xiaokunhou default key is list or array, See private Object wrapCollection(final Object object) {
if (object instanceof List) {
StrictMap<Object> map = new StrictMap<Object>();
map.put("list", object);
return map;
} else if (object != null && object.getClass().isArray()) {
StrictMap<Object> map = new StrictMap<Object>();
map.put("array", object);
return map;
}
return object;
} |
@xiaokunhou When your method has more than one arguments, you must assign |
@abel533 you answered my first question. For the second problem, this fix cannot handle collections with a customized key with |
Is it fixed, bug with no id, after array is passed to insert? |
I'm using latest 3.4.1, however, this issue seems still existing to me.
RawCell:
This is the error:
|
@neesonqk try to use |
@xiaokunhou it's a bit weird since I imported the latest source code to my project rather than pulling from Maven repository, this exception's gone, but I'm sure I imported the proper 3.4.0.jar within my pom.xml.
is that possible a wrong jar package pushed to Maven center repository? I mean in a sense? N It works well without @param("list") annotation. |
Hi guys, thanks for feedback! If there are problem or some enhancement point, please create a new issue that related with this issue. (Because this enhancement has been released already) |
fixed via #547 |
I user oracle , When insert a list ,it throw Exception.(### Cause: java.sql.SQLSyntaxErrorException: ORA-00933: )
|
When insert a list or array,resolve the useGeneratedKeys error.
The Sample:
Mapper.xml File:
The Java code File:
Solution
Add a method to handle the parameters:
Add a first Key
keys
,and then developer can usekeys
to specify the reveive param.If not specif,find
list
orarray
.If not existed,use theparameter
only.Note:use
Collection
support more thanList
,likeSet
.