Details
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserAttributeEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserAttributeEntity.java
index 16b155b..5341b64 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserAttributeEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserAttributeEntity.java
@@ -43,7 +43,7 @@ import java.util.Set;
@NamedQuery(name="getAttributesByNameAndValue", query="select attr from UserAttributeEntity attr where attr.name = :name and attr.value = :value"),
@NamedQuery(name="deleteUserAttributesByRealm", query="delete from UserAttributeEntity attr where attr.user IN (select u from UserEntity u where u.realmId=:realmId)"),
@NamedQuery(name="deleteUserAttributesByNameAndUser", query="delete from UserAttributeEntity attr where attr.user.id = :userId and attr.name = :name"),
- @NamedQuery(name="deleteUserAttributesOtherThan", query="delete from UserAttributeEntity attr where attr.user.id = :userId and attr.id <> :attrId"),
+ @NamedQuery(name="deleteUserAttributesByNameAndUserOtherThan", query="delete from UserAttributeEntity attr where attr.user.id = :userId and attr.name = :name and attr.id <> :attrId"),
@NamedQuery(name="deleteUserAttributesByRealmAndLink", query="delete from UserAttributeEntity attr where attr.user IN (select u from UserEntity u where u.realmId=:realmId and u.federationLink=:link)")
})
@Table(name="USER_ATTRIBUTE")
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/UserAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/UserAdapter.java
index 49bcac6..7f475f5 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/UserAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/UserAdapter.java
@@ -140,9 +140,10 @@ public class UserAdapter implements UserModel, JpaModel<UserEntity> {
if (firstExistingAttrId != null) {
// Remove attributes through HQL to avoid StaleUpdateException
- Query query = em.createNamedQuery("deleteUserAttributesOtherThan");
- query.setParameter("attrId", firstExistingAttrId);
+ Query query = em.createNamedQuery("deleteUserAttributesByNameAndUserOtherThan");
+ query.setParameter("name", name);
query.setParameter("userId", user.getId());
+ query.setParameter("attrId", firstExistingAttrId);
int numUpdated = query.executeUpdate();
// Remove attribute from local entity
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserModelTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserModelTest.java
index e2af241..1854d2d 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserModelTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserModelTest.java
@@ -17,6 +17,7 @@
package org.keycloak.testsuite.model;
+import com.google.common.collect.ImmutableMap;
import org.junit.Assert;
import org.junit.Test;
import org.keycloak.models.ClientModel;
@@ -216,8 +217,8 @@ public class UserModelTest extends AbstractModelTest {
public void testUpdateUserAttribute() throws Exception {
RealmModel realm = realmManager.createRealm("original");
UserModel user = session.users().addUser(realm, "user");
-
- user.setSingleAttribute("key1", "value1");
+
+ user.setSingleAttribute("key1", "value1");
commit();
@@ -235,6 +236,30 @@ public class UserModelTest extends AbstractModelTest {
commit();
}
+
+ // KEYCLOAK-3608
+ @Test
+ public void testUpdateUserSingleAttribute() {
+ Map<String, List<String>> expected = ImmutableMap.of(
+ "key1", Arrays.asList("value3"),
+ "key2", Arrays.asList("value2"));
+
+ RealmModel realm = realmManager.createRealm("original");
+ UserModel user = session.users().addUser(realm, "user");
+
+ user.setSingleAttribute("key1", "value1");
+ user.setSingleAttribute("key2", "value2");
+
+ // Overwrite the first attribute
+ user.setSingleAttribute("key1", "value3");
+
+ Assert.assertEquals(expected, user.getAttributes());
+
+ commit();
+
+ realm = session.realms().getRealmByName("original");
+ Assert.assertEquals(expected, session.users().getUserByUsername("user", realm).getAttributes());
+ }
@Test
public void testSearchByString() {