JPA EntityManager: ¿Por qué usar persist() sobre merge()?


EntityManager.merge() puede insertar nuevos objetos y actualizar los existentes.

¿Por qué uno querría usar persist() (que solo puede crear nuevos objetos)?

Author: Harshal Patil, 2009-07-01

15 answers

De cualquier manera agregará una entidad a un PersistenceContext, la diferencia está en lo que haga con la entidad después.

Persist toma una instancia de entidad, la agrega al contexto y hace que esa instancia sea administrada (es decir, se rastrearán las actualizaciones futuras de la entidad).

Merge crea una nueva instancia de su entidad, copia el estado de la entidad suministrada y administra la nueva copia. La instancia que pase no se administrará (los cambios que realice no formarán parte del transaction-a menos que vuelva a llamar a merge).

Tal vez un ejemplo de código ayude.

MyEntity e = new MyEntity();

// scenario 1
// tran starts
em.persist(e); 
e.setSomeField(someValue); 
// tran ends, and the row for someField is updated in the database

// scenario 2
// tran starts
e = new MyEntity();
em.merge(e);
e.setSomeField(anotherValue); 
// tran ends but the row for someField is not updated in the database
// (you made the changes *after* merging)

// scenario 3
// tran starts
e = new MyEntity();
MyEntity e2 = em.merge(e);
e2.setSomeField(anotherValue); 
// tran ends and the row for someField is updated
// (the changes were made to e2, not e)

Los escenarios 1 y 3 son aproximadamente equivalentes, pero hay algunas situaciones en las que querría usar el Escenario 2.

 1479
Author: Mike,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-27 11:56:38

Persist y merge son para dos propósitos diferentes (no son alternativas en absoluto).

(editado para expandir la información de diferencias)

Persist:

  • Insertar un nuevo registro en la base de datos
  • Adjunte el objeto al entity manager.

Merge:

  • Encuentre un objeto adjunto con el mismo id y actualícelo.
  • Si existe actualice y devuelva el objeto ya adjunto.
  • Si no existe inserte el nuevo registro para base.

Persist() eficiencia:

  • Podría ser más eficiente para insertar un nuevo registro en una base de datos que merge().
  • No duplica el objeto original.

Persist() semántica:

  • Se asegura de que está insertando y no actualizando por error.

Ejemplo:

{
    AnyEntity newEntity;
    AnyEntity nonAttachedEntity;
    AnyEntity attachedEntity;

    // Create a new entity and persist it        
    newEntity = new AnyEntity();
    em.persist(newEntity);

    // Save 1 to the database at next flush
    newEntity.setValue(1);

    // Create a new entity with the same Id than the persisted one.
    AnyEntity nonAttachedEntity = new AnyEntity();
    nonAttachedEntity.setId(newEntity.getId());

    // Save 2 to the database at next flush instead of 1!!!
    nonAttachedEntity.setValue(2);
    attachedEntity = em.merge(nonAttachedEntity);

    // This condition returns true
    // merge has found the already attached object (newEntity) and returns it.
    if(attachedEntity==newEntity) {
            System.out.print("They are the same object!");
    }

    // Set 3 to value
    attachedEntity.setValue(3);
    // Really, now both are the same object. Prints 3
    System.out.println(newEntity.getValue());

    // Modify the un attached object has no effect to the entity manager
    // nor to the other objects
    nonAttachedEntity.setValue(42);
}

De esta manera solo existe 1 objeto adjunto para cualquier registro en el entity manager.

Merge () para una entidad con un id es algo así como:

AnyEntity myMerge(AnyEntity entityToSave) {
    AnyEntity attached = em.find(AnyEntity.class, entityToSave.getId());
    if(attached==null) {
            attached = new AnyEntity();
            em.persist(attached);
    }
    BeanUtils.copyProperties(attached, entityToSave);

    return attached;
}

Aunque si se conecta a MySQL merge() podría ser tan eficiente como persist() usando una llamada para INSERTAR con la opción ON DUPLICATE KEY UPDATE, JPA es una programación de muy alto nivel y no se puede asumir que esto va a ser el caso en todas partes.

 153
Author: Josep Panadero,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-15 09:11:41

Si está utilizando el generador asignado, usar merge en lugar de persist puede causar una sentencia SQL redundante, lo que afecta el rendimiento.

Además, llamar a merge para entidades administradastambién es un error, ya que las entidades administradas son administradas automáticamente por Hibernate y su estado se sincroniza con el registro de la base de datos mediante el mecanismo de verificación sucia al vaciar el Contexto de Persistencia.

Para entender cómo funciona todo esto, primero debe saber que Hibernate cambia la mentalidad del desarrollador de instrucciones SQL a transiciones de estado de entidad.

Una vez que una entidad es gestionada activamente por Hibernate, todos los cambios se propagarán automáticamente a la base de datos.

Hibernate monitors entidades actualmente adjuntas. Pero para que una entidad sea administrada, debe estar en el estado de entidad correcto.

Primero, debemos definir todos los estados de entidad:

  • Nuevo (transitorio)

    A el objeto recién creado que nunca se ha asociado con un Hibernate Session (también conocido como Persistence Context) y no está asignado a ninguna fila de tabla de la base de datos se considera que está en el estado Nuevo (Transitorio).

    Para ser persistido necesitamos llamar explícitamente al método EntityManager#persist o hacer uso del mecanismo de persistencia transitiva.

  • Persistente (Administrado)

    Se ha asociado una entidad persistente con una fila de tabla de la base de datos y está siendo administrada por la ejecución actual Contexto de Persistencia. Cualquier cambio realizado en dicha entidad será detectado y propagado a la base de datos (durante el tiempo de descarga de la sesión). Con Hibernate, ya no tenemos que ejecutar instrucciones INSERT/UPDATE/DELETE. Hibernate emplea un estilo de trabajo transaccional write-behind y los cambios se sincronizan en el último momento responsable, durante el actual Session flush-time.

  • Separado

    Una vez que se cierra el contexto de Persistencia en ejecución las entidades previamente administradas se separan. Los cambios sucesivos ya no se rastrearán y no se realizará ninguna sincronización automática de la base de datos.

    Para asociar una entidad separada a una sesión de Hibernación activa, puede elegir una de las siguientes opciones:

    • Volver a conectar

      Hibernate (pero no JPA 2.1) soporta volver a conectar a través del método Session#update. Una sesión de Hibernación solo puede asociar un objeto de entidad para una fila de base de datos dada. Esto es debido a que el Contexto de Persistencia actúa como una caché en memoria (caché de primer nivel) y solo un valor (entidad) está asociado a una clave dada (tipo de entidad e identificador de base de datos). Una entidad se puede volver a conectar solo si no hay otro objeto JVM (que coincida con la misma fila de la base de datos) ya asociado a la sesión de Hibernación actual.

    • Fusión

    La fusión va a copiar el estado de entidad separada (fuente) a una instancia de entidad administrada (destino). Si el la entidad fusionada no tiene equivalente en la sesión actual, se obtendrá uno de la base de datos. La instancia de objeto separado seguirá estando separada incluso después de la operación de fusión.

  • Eliminado

    Aunque JPA exige que solo se permita eliminar las entidades administradas, Hibernate también puede eliminar entidades separadas (pero solo a través de una llamada al método Session#delete). Una entidad eliminada solo está programada para su eliminación y la declaración de ELIMINACIÓN de la base de datos real será ejecutado durante el tiempo de descarga de la sesión.

Para entender mejor las transiciones de estado de JPA, puede visualizar el siguiente diagrama:

introduzca la descripción de la imagen aquí

O si utiliza la API específica de Hibernación:

introduzca la descripción de la imagen aquí

 113
Author: Vlad Mihalcea,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-04 06:22:59

Noté que cuando usé em.merge, obtuve una instrucción SELECT para cada INSERT, incluso cuando no había ningún campo que JPA estaba generando para mí the el campo de clave primaria era un UUID que yo mismo establecí. Cambié a em.persist(myEntityObject) y obtuve solo INSERT declaraciones entonces.

 37
Author: Sarah Vessels,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-01-18 21:14:31

La especificación JPA dice lo siguiente acerca de persist().

Si X es un objeto separado, el EntityExistsException puede ser lanzado cuando el persist se invoca la operación, o el EntityExistsException u otro PersistenceException puede ser lanzado al flush o al commit time.

Así que usar persist()sería adecuado cuando el objeto no debería ser un objeto separado. Es posible que prefiera que el código arroje el PersistenceException para que falle rápido.

Aunque la especificación es poco claro, persist() podría establecer el @GeneratedValue @Id por un objeto. merge() sin embargo debe tener un objeto con el @Id ya generado.

 28
Author: Raedwald,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:34:48

Algunos detalles más sobre merge que le ayudarán a usar merge sobre persist:

Devolver una instancia administrada que no sea la entidad original es una parte crítica de la fusión proceso. Si ya existe una instancia de entidad con el mismo identificador en el contexto de persistencia, el proveedor sobrescribirá su estado con el estado de la entidad que se está fusionando, pero la versión que ya existía debe ser devuelta al cliente para que pueda ser utilizada. Si el el proveedor no actualizar la instancia de Empleado en el contexto de persistencia, cualquier referencia a esa instancia se convertirá en inconsistente con el nuevo estado que se fusiona en.

Cuando se invoca merge() en una entidad nueva, se comporta de manera similar a la operación persist (). Añade la entidad al contexto de persistencia, pero en lugar de agregar la instancia de entidad original, crea una nueva copie y administre esa instancia en su lugar. La copia que se crea mediante la operación merge () es persistir como si el método persist() fuera invocado en él.

En presencia de relaciones, la operación merge() intentará actualizar la entidad administrada para apuntar a las versiones administradas de las entidades referenciadas por la entidad separada. Si la entidad tiene un relación con un objeto que no tiene identidad persistente, el resultado de la operación de fusión es indefinido. Algunos proveedores pueden permitir que la copia administrada apunte al objeto no persistente, mientras que otros podrían lanzar una excepción inmediata. La operación merge() puede ser opcionalmente en cascada en estos casos para evitar que ocurra una excepción. Cubriremos la cascada de la fusión() operación más adelante en esta sección. Si una entidad que se fusiona apunta a una entidad eliminada, un Se lanzará la excepción IllegalArgumentException.

Las relaciones de carga lenta son un caso especial en la operación de fusión. Si una carga perezosa relación no se desencadenó en una entidad antes de que se separó, que la relación será se ignora cuando se fusiona la entidad. Si la relación se activó mientras se administraba y luego se estableció en null mientras se separaba la entidad, la versión administrada de la entidad también tendrá la relación borrada durante la fusión."

Toda la información anterior fue tomada de "Pro JPA 2 Mastering the Java™ Persistence API" por Mike Keith y Merrick Schnicariol. Capítulo 6. Separación de la sección y fusión. Este libro es en realidad un segundo libro dedicado a JPA por autores. Este nuevo libro tiene mucha información nueva entonces anterior. Realmente recomendé leer este libro para aquellos que estarán seriamente involucrados con JPA. Lo siento por publicar anonimously mi primera respuesta.

 16
Author: Khurshed Salimov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-05 14:11:52

Hay algunas diferencias más entre merge y persist (Enumeraré de nuevo las ya publicadas aquí):

D1. merge no hace que la entidad pasada sea administrada, sino que devuelve otra instancia que es administrada. persist en el otro lado hará que la entidad pasada sea administrada:

//MERGE: passedEntity remains unmanaged, but newEntity will be managed
Entity newEntity = em.merge(passedEntity);

//PERSIST: passedEntity will be managed after this
em.persist(passedEntity);

D2. Si elimina una entidad y luego decide persistir la entidad de nuevo, puede hacerlo solo con persist (), porque merge lanzará un IllegalArgumentException.

D3. Si usted decidió tomar cuidado manualmente de sus ID (por ejemplo, mediante el uso de UUID), a continuación, un merge la operación activará posteriores consultas SELECT para buscar entidades existentes con ese ID, mientras que persist puede no necesitar esas consultas.

D4. Hay casos en los que simplemente no confía en el código que llama a su código, y para asegurarse de que no se actualice ningún dato, sino que se inserte, debe usar persist.

 15
Author: Andrei I,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-02 14:13:56

Estaba recibiendo excepciones de LazyLoading en mi entidad porque estaba tratando de acceder a una colección lazy loaded que estaba en sesión.

Lo que haría era en una solicitud separada, recuperar la entidad de la sesión y luego tratar de acceder a una colección en mi página jsp que era problemática.

Para aliviar esto, actualizé la misma entidad en mi controlador y la pasé a mi jsp, aunque imagino que cuando vuelva a guardarla en sesión también será accesible aunque SessionScope y no lanzará a LazyLoadingException, una modificación del ejemplo 2:

Lo siguiente ha funcionado para mí:

// scenario 2 MY WAY
// tran starts
e = new MyEntity();
e = em.merge(e); // re-assign to the same entity "e"

//access e from jsp and it will work dandy!!
 8
Author: logixplayer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-01-21 11:01:11

Pasando por las respuestas hay algunos detalles que faltan con respecto a `Cascada' y la generación de id. Ver pregunta

Además, vale la pena mencionar que puede tener Cascade anotaciones separadas para fusionar y persistir: Cascade.MERGE y Cascade.PERSIST que se tratarán de acuerdo con el método utilizado.

La especificación es tu amiga;)

 6
Author: Ioannis Deligiannis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:47:26

Escenario X:

Tabla: Spitter (Uno) ,Tabla: Spittles (Muchos) (Spittles es Dueño de la relación con un FK:spitter_id)

Este escenario resulta en guardar : El Spitter y ambos Spittles como si fueran propiedad del Mismo Spitter.

        Spitter spitter=new Spitter();  
    Spittle spittle3=new Spittle();     
    spitter.setUsername("George");
    spitter.setPassword("test1234");
    spittle3.setSpittle("I love java 2");       
    spittle3.setSpitter(spitter);               
    dao.addSpittle(spittle3); // <--persist     
    Spittle spittle=new Spittle();
    spittle.setSpittle("I love java");
    spittle.setSpitter(spitter);        
    dao.saveSpittle(spittle); //<-- merge!!

Escenario Y:

Esto salvará al Escupidor, salvará a los 2 Escupidores, ¡pero no harán referencia al mismo Escupidor!

        Spitter spitter=new Spitter();  
    Spittle spittle3=new Spittle();     
    spitter.setUsername("George");
    spitter.setPassword("test1234");
    spittle3.setSpittle("I love java 2");       
    spittle3.setSpitter(spitter);               
    dao.save(spittle3); // <--merge!!       
    Spittle spittle=new Spittle();
    spittle.setSpittle("I love java");
    spittle.setSpitter(spitter);        
    dao.saveSpittle(spittle); //<-- merge!!
 5
Author: George Papatheodorou,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-28 18:06:38

Encontré esta explicación de los documentos de Hibernación esclarecedora, porque contienen un caso de uso:

El uso y la semántica de merge() parece ser confuso para los nuevos usuarios. En primer lugar, mientras no esté tratando de usar el estado de objeto cargado en un administrador de entidades en otro nuevo administrador de entidades, no debería usar merge() en absoluto. Algunas aplicaciones enteras nunca usarán este método.

Normalmente se usa merge() en el siguiente escenario:

  • La aplicación carga un objeto en el primer entity manager
  • el objeto se pasa a la capa de presentación
  • se hacen algunas modificaciones al objeto
  • el objeto se devuelve a la capa lógica de negocio
  • la aplicación persiste estas modificaciones llamando a merge () en un segundo entity manager

Aquí está la semántica exacta de merge ():

  • si hay una instancia administrada con el mismo identificador actualmente asociado con el contexto de persistencia, copie el estado del objeto dado en la instancia administrada
  • si no hay ninguna instancia administrada actualmente asociada con el contexto de persistencia, intente cargarla desde la base de datos o cree una nueva instancia administrada
  • se devuelve la instancia administrada
  • la instancia dada no se asocia con el contexto de persistencia, permanece separada y generalmente se descarta

De: http://docs.jboss.org/hibernate/entitymanager/3.6/reference/en/html/objectstate.html

 5
Author: Ray Hulha,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-18 16:28:54

JPA es indiscutiblemente una gran simplificación en el ámbito de la empresa aplicaciones construidas en la plataforma Java. Como desarrollador que tuvo que hacer frente a las complejidades de los viejos frijoles entidad en J2EE Veo el inclusión de JPA entre las especificaciones de Java EE como un gran salto adelante. Sin embargo, mientras profundizo en los detalles de JPA, encuentro cosas que no son tan fáciles. En este artículo me ocupo de la comparación de los métodos merge y persist de EntityManager cuyos solapar el comportamiento puede causar confusión no solo a un novato. Además proponer una generalización que vea ambos métodos como casos especiales de un método más general combinar.

Entidades persistentes

En contraste con el método merge, el método persist es bastante sencillo e intuitivo. El escenario más común del uso del método persist se puede resumir de la siguiente manera:

" Una instancia recién creada de la clase entity se pasa al persist método. Después de que este método regresa, la entidad es administrada y planificada para su inserción en la base de datos. Puede ocurrir en o antes de que la transacción se confirme o cuando se llame al método flush. Si la entidad hace referencia a otra entidad a través de una relación marcada con la estrategia de cascada PERSIST, este procedimiento también se aplica a ella."

introduzca la descripción de la imagen aquí

La especificación entra más en detalles, sin embargo, recordarlos no es crucial ya que estos detalles cubren más o menos exóticos solo situaciones.

Entidades fusionadas

En comparación con persist, la descripción del comportamiento de la fusión no es tan simple. No hay un escenario principal, como es en el caso de persist, y un programador debe recordar todos los escenarios para escribir un código correcto. Me parece que los diseñadores de JPA querían tener algún método cuya principal preocupación sería manejar entidades separadas (como lo opuesto al método persist que trata con entidades recién creadas principalmente.) La tarea principal del método merge es transferir el estado de una entidad no administrada (pasada como argumento) a su contraparte administrada dentro del contexto de persistencia. Esta tarea, sin embargo, se divide aún más en varios escenarios que empeoran la inteligibilidad del comportamiento general del método.

En lugar de repetir párrafos de la especificación JPA, he preparado un diagrama de flujo que muestra esquemáticamente el comportamiento de la fusión método:

introduzca la descripción de la imagen aquí

Entonces, ¿cuándo debo usar persist y cuándo fusionar?

Persist

  • Desea que el método siempre cree una nueva entidad y nunca actualice una entidad. De lo contrario, el método lanza una excepción como consecuencia de la violación de unicidad de clave primaria.
  • Procesos por lotes, manejando entidades de una manera con estado (ver patrón de puerta de enlace).
  • Rendimiento optimización

Merge

  • Desea que el método inserte o actualice una entidad en la base de datos.
  • Desea manejar entidades de manera sin estado (objetos de transferencia de datos en servicios)
  • Desea insertar una nueva entidad que puede tener una referencia a otra entidad que puede pero no puede ser creada todavía (la relación debe marcarse como MERGE). Por ejemplo, insertar una foto nueva con una referencia a una nueva o preexistente Album.
 5
Author: Amit Gujarathi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-06 12:36:08

Puede haber venido aquí para obtener consejos sobre cuándo usar persist y cuándo usar merge. Creo que depende de la situación: qué tan probable es que necesite crear un nuevo registro y qué tan difícil es recuperar los datos persistentes.

Supongamos que puede usar una clave/identificador natural.

  • Los datos deben persistir, pero de vez en cuando existe un registro y se requiere una actualización. En este caso usted podría intentar un persist y si lanza un EntityExistsException, lo busca y combina los datos:

    Intenta { EntityManager.persist (entity) }

    Catch (EntityExistsException exception) { /* recuperar y fusionar */ }

  • Los datos persistentes deben actualizarse, pero de vez en cuando todavía no hay registro de los datos. En este caso se busca, y hacer un persist si la entidad falta:

    Entity = EntityManager.buscar (clave);

    If (entity == null) { EntityManager.persist (entidad); }

    Else {/*merge*/}

Si no tiene clave/identificador natural, tendrá más dificultades para averiguar si la entidad existe o no, o cómo buscarla.

Las fusiones también se pueden tratar de dos maneras:

  1. Si los cambios son generalmente pequeños, aplíquelos a la entidad administrada.
  2. Si los cambios son comunes, copie el ID de la entidad persistida, así como los datos inalterados. Luego llama a EntityManager:: merge() para reemplazar el antiguo contenido.
 1
Author: Peter Willems,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-06 20:15:10

Persist(entity) se debe usar con entidades totalmente nuevas, para agregarlas a DB (si entity ya existe en DB habrá EntityExistsException throw).

Se debe usar Merge(entity), para devolver la entidad al contexto de persistencia si la entidad se separó y se cambió.

Probablemente persist está generando la instrucción INSERT sql y la instrucción merge UPDATE sql (pero no estoy seguro).

 0
Author: Krystian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-04 12:38:37

Otra observación:

merge() solo le importará un id generado automáticamente (probado en IDENTITY y SEQUENCE) cuando ya exista un registro con dicho id en su tabla. En ese caso merge() intentará actualizar el registro. Sin embargo, si un id está ausente o no coincide con ningún registro existente, merge() lo ignorará completamente y pedirá a una bd que asigne uno nuevo. Esto es a veces una fuente de muchos errores. No utilice merge() para forzar un id para un nuevo registro.

persist() por otro lado se nunca dejes que le pases una identificación. Fallará inmediatamente. En mi caso, es:

Causado por: org.hibernación.PersistentObjectException: detached entity pasado a persist

Hibernación-jpa javadoc tiene una pista:

Lanza : javax.persistencia.EntityExistsException - si la entidad ya existe. (Si la entidad ya existe, el EntityExistsException se puede lanzar cuando la operación persist invocado, o la EntityExistsException u otra PersistenceException puede ser lanzado en color o tiempo de compromiso.)

 0
Author: yuranos87,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-01 15:06:49