<?xml version='1.0' encoding='UTF-8'?><rss xmlns:atom='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0' version='2.0'><channel><atom:id>tag:blogger.com,1999:blog-8618841044787531046</atom:id><lastBuildDate>Sun, 20 May 2012 21:13:34 +0000</lastBuildDate><category>real world</category><category>hibernate</category><category>real world java</category><category>javascript</category><category>java</category><category>web</category><category>autobombo</category><category>desfirewrapper</category><category>REST</category><category>ajax</category><category>delegados</category><category>conocimiento casual</category><category>vm</category><category>certificados digitales</category><category>oop</category><category>lambda</category><category>arquitectura</category><category>lo leí en un blog</category><category>buenas prácticas</category><category>powershell</category><category>web 2.0</category><category>mac</category><category>windows</category><category>.net</category><category>entity framework</category><category>nhibernate</category><category>base de datos</category><category>svn</category><category>humor</category><title>No compila ...</title><description>Memorias, opiniones y vivencias. Java y .Net.</description><link>http://www.nocompila.com/</link><managingEditor>noreply@blogger.com (Admin)</managingEditor><generator>Blogger</generator><openSearch:totalResults>42</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8618841044787531046.post-3140845452996414326</guid><pubDate>Mon, 07 May 2012 15:10:00 +0000</pubDate><atom:updated>2012-05-07T17:12:12.236+02:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>java</category><category domain='http://www.blogger.com/atom/ns#'>humor</category><title>Festival del Humor (V)</title><description>Código para copiar Lists &lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:java;"&gt;// (...)&lt;br /&gt;List&amp;lt;Pais&gt; escalas = (List) RemoteUtil.getSessionBean(Constantes.LISTA_ESCALAS, false);&lt;br /&gt;List&amp;lt;Pais&gt; escalasTemp = new ArrayList&amp;lt;Pais&gt;();&lt;br /&gt;if (escalas != null &amp;&amp; escalas.size() &gt; 0) {&lt;br /&gt;    escalasTemp = new ArrayList(Arrays.asList(new Pais[escalas.size()]));&lt;br /&gt;    Collections.copy(escalasTemp, escalas);&lt;br /&gt;}&lt;br /&gt;// (...)&lt;br /&gt;&lt;/pre&gt;Cortesía de E.B.&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8618841044787531046-3140845452996414326?l=www.nocompila.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.nocompila.com/2012/05/festival-del-humor-v.html</link><author>noreply@blogger.com (Pedro)</author><thr:total>2</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8618841044787531046.post-485684902900876400</guid><pubDate>Thu, 03 May 2012 22:30:00 +0000</pubDate><atom:updated>2012-05-04T09:16:00.408+02:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>vm</category><category domain='http://www.blogger.com/atom/ns#'>real world</category><title>Compactando imágenes de disco en VirtualBox</title><description>&lt;div style="font-family: Verdana,sans-serif; text-align: justify;"&gt;&lt;br /&gt;Cuando se afronta la configuración de una máquina virtual, una de las  dudas que se suelen plantear gira en torno a la definición de los  discos virtuales. Hoy en día, todos los software de máquinas virtuales  (VirtualBox, VMWare, ...) &amp;nbsp;ofrecen la posibilidad de elegir si los  ficheros de imagen de los discos virtuales van a ser estáticos o  dinámicos.&lt;/div&gt;&lt;div style="font-family: Verdana,sans-serif; text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: Verdana,sans-serif; text-align: justify;"&gt;Los discos virtuales estáticos reservan el espacio  completo de la capacidad de la máquina virtual en el momento de su  creación. Por el contrario, las &amp;nbsp;imágenes dinámicas se inicializan con  un tamaño pequeño y, según va siendo necesario más espacio, la imagen  del disco dinámico va creciendo. Este crecimiento es siempre 'a más' ,  ya que por mucho que se libere espacio en el sistema &lt;i&gt;guest&amp;nbsp;&lt;/i&gt;la imagen no va a ver reducido su tamaño salvo que se realice un procedimiento de &lt;i&gt;compactación&amp;nbsp;&lt;/i&gt;.&lt;/div&gt;&lt;div style="font-family: Verdana,sans-serif; text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: Verdana,sans-serif; text-align: justify;"&gt;En  entornos virtualizados de producción la decisión más adecuada suele ser  la definición de discos con tamaño estático.El rendimiento de este tipo  de imágenes es más rápido y no se pierde rendimiento en reservas de  nuevo espacio en el &lt;i&gt;host &lt;/i&gt;.&lt;/div&gt;&lt;div style="font-family: Verdana,sans-serif; text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: Verdana,sans-serif; text-align: justify;"&gt;Sin embargo, en entornos de desarrollo, en los que el espacio de los discos del &lt;i&gt;host&amp;nbsp;&lt;/i&gt;suele ser un factor limitante, suele ser más interesante reservarlos de manera dinámica.&lt;/div&gt;&lt;h2 id="HSituaciF3n" style="font-family: Verdana,sans-serif; text-align: justify;"&gt;           Situación&lt;/h2&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="edit_section" style="font-family: Verdana,sans-serif;"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="font-family: Verdana,sans-serif; text-align: justify;"&gt;En  un entorno de trabajo con una máquina virtual con imágenes dinámicas es  probable que en un cierto momento el disco crezca de tamaño - por  ejemplo, en una instalación de un software - para después volver a ver  reducido su tamaño. Cuando esto ocurre, la imagen no ve reducido su  tamaño de nuevo.&amp;nbsp;&lt;/div&gt;&lt;div style="font-family: Verdana,sans-serif; text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: Verdana,sans-serif; text-align: justify;"&gt;Por ejemplo:&lt;/div&gt;&lt;div style="font-family: Verdana,sans-serif; text-align: justify;"&gt;&lt;i&gt;sobre una máquina Linux vacía,  con un disco dinámico de tamaño máximo 20GB y &amp;nbsp;tamaño real de 1GB, vamos  a instalar un WAS. Para ello, es necesario copiar los binarios a la  máquina (1,5 GB ) , descomprimirlos (4 GB) , e instalarlos ( 2 GB) .  Además, durante el proceso de instalación se crean un conjunto de  ficheros temporales que pueden ocupar algún giga más. Al terminar el  proceso de instalación, es probable que el disco ocupe unos 10 GB,  cuando realmente sólo harían falta unos 3 GB.&lt;/i&gt;&lt;/div&gt;&lt;div style="font-family: Verdana,sans-serif; text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: Verdana,sans-serif; text-align: justify;"&gt;¿Para qué  necesitamos un disco ocupando 10 GB en este caso? Podríamos borrar los  ficheros que no usamos. Escribimos los comandos &lt;i&gt;rm&amp;nbsp;&lt;/i&gt;que procedan y dejaríamos la máquina con esos 3GB ocupados - por ejemplo, se podría comprobar con el comando &lt;i&gt;df&amp;nbsp;&amp;nbsp;&lt;/i&gt;de Linux - .Pero  el fichero de imagen sigue ocupando 10GB. &amp;nbsp;¿Cómo solucionarlo?  Utilizando las herramientas de compactación del software de máquina  virtual.&lt;/div&gt;&lt;h2 id="HCompactando...28I29" style="font-family: Verdana,sans-serif; text-align: justify;"&gt;           Compactando... (I)&lt;/h2&gt;&lt;div style="font-family: Verdana,sans-serif; text-align: justify;"&gt;Las  herramientas de compactación que ofrecen tanto VMWare como VirtualBox  localizan bloques en disco con ceros escritos, y liberan ese espacio del  fichero de imagen dinámica.&lt;/div&gt;&lt;div style="font-family: Verdana,sans-serif; text-align: justify;"&gt;Por ejemplo, la herramienta de VirtualBox tiene la sintaxis&lt;/div&gt;&lt;div style="font-family: Verdana,sans-serif; text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="box code" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace; text-align: justify;"&gt;C:&lt;span style="color: #bb6622; font-weight: bold;"&gt;\P&lt;/span&gt;rogram Files&lt;span style="color: #bb6622; font-weight: bold;"&gt;\O&lt;/span&gt;racle&lt;span style="color: #bb6622; font-weight: bold;"&gt;\V&lt;/span&gt;irtualBox&lt;span style="color: #bb6622; font-weight: bold;"&gt;\V&lt;/span&gt;BoxManage.exe modifyhd &amp;lt;ficheroImagen.vdi&amp;gt; -compact&lt;/div&gt;&lt;div class="box code" style="font-family: Verdana,sans-serif; text-align: justify;"&gt;&lt;/div&gt;&lt;div style="font-family: Verdana,sans-serif; text-align: justify;"&gt;Si  pasamos esta herramienta por nuestra imagen de disco gigante debería  devolverla a los 3GB esperados. Sin embargo, al ejecutarla sobre la  imagen de disco y después de un rato, vemos con gran pena que el tamaño  permanece inmutable.&lt;/div&gt;&lt;div style="font-family: Verdana,sans-serif; text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: Verdana,sans-serif; text-align: justify;"&gt;¿Por qué?&lt;/div&gt;&lt;div style="font-family: Verdana,sans-serif; text-align: justify;"&gt;Por la forma en la que los  sistemas operativos borran ficheros. Cuando un sistema operativo borra  un fichero lo que suele hacer es eliminarlo de las tablas de asignación  de ficheros, de manera que sus sectores vuelven a estar disponibles para  nuevos ficheros. Sin embargo, el espacio de disco no se escribe con  ceros.&lt;/div&gt;&lt;div style="font-family: Verdana,sans-serif; text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: Verdana,sans-serif; text-align: justify;"&gt;¿Y entonces?&lt;/div&gt;&lt;div style="font-family: Verdana,sans-serif; text-align: justify;"&gt;Pues habrá que escribir con ceros el espacio de disco no usado antes de compactar.&lt;/div&gt;&lt;h2 id="HZero-filling" style="font-family: Verdana,sans-serif; text-align: justify;"&gt;           Zero-filling&lt;/h2&gt;&lt;div style="font-family: Verdana,sans-serif; text-align: justify;"&gt;Aunque  en Windows la solución es análoga, nos vamos a centrar en la solución  para Linux. Hay dos maneras principales de hacer la operación de  escritura a cero de la información de los bloques de disco vacíos. O  haciendo un &lt;i&gt;wiping&lt;/i&gt; -borrado seguro- en cada operación de  borrado de ficheros - que degrada mucho el rendimiento de la máquina  virtual- , o haciendo una operación de&lt;span style="font-style: italic;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="font-style: normal;"&gt;mantenimiento de&amp;nbsp;&lt;/span&gt;&lt;i&gt;zerofilling&amp;nbsp;&lt;/i&gt;de los bloques borrados antes de hacer la compactación. Esta será nuestra opción.&lt;/div&gt;&lt;div style="font-family: Verdana,sans-serif; text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: Verdana,sans-serif; text-align: justify;"&gt;Los pasos siguientes son para CentOS / RHEL , aunque en otras distribuciones va a ser muy similar.&lt;/div&gt;&lt;div style="font-family: Verdana,sans-serif; text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="box infomessage" style="font-family: Verdana,sans-serif; text-align: justify;"&gt;Como  precondición, habrá que instalar la utilidad &lt;i&gt;zerofree &lt;/i&gt;en el sistema &lt;i&gt;guest&lt;/i&gt; , disponible en los repositorios &lt;i&gt;3rd party&lt;/i&gt; de casi todas las  distribuciones.&amp;nbsp;&lt;/div&gt;&lt;ol style="font-family: Verdana,sans-serif; text-align: justify;"&gt;&lt;li&gt;Reiniciar la máquina virtual&lt;/li&gt;&lt;li&gt;Pulsar &lt;i&gt;&amp;lt;ESC&amp;gt;&lt;/i&gt; en el menú de grub.&lt;/li&gt;&lt;li&gt;Seleccionar la opción en grub que arranque el sistema en modo &lt;i&gt;rescue&amp;nbsp;&lt;/i&gt;, o si no existe, localizar la opción que arranque el sistema de modo normal y pulsar la tecla &lt;i&gt;&amp;lt;a&amp;gt;&lt;/i&gt; . Esto entrará el modo &lt;i&gt;append&amp;nbsp;&amp;nbsp;&lt;/i&gt;de grub .&lt;/li&gt;&lt;li&gt;Añadir, al final de la linea, la palabra &lt;i&gt;single&amp;nbsp;&lt;/i&gt;. Esto hará que Linux arranque en modo single user, sin red, pero con la posibilidad de desmontar el sistema de ficheros raíz.&amp;nbsp;&lt;/li&gt;&lt;li&gt;Una  vez que el sistema haya arrancado y esté en el prompt &amp;nbsp;- un signo de  que todo ha ido correctamente es que llega al prompt sin pasar por una  pantalla de login - , habrá que desmontar el sistema de ficheros y  volver a montarlo en modo &lt;i&gt;readonly.&amp;nbsp;&lt;/i&gt;Para comprobar en qué  sistema de ficheros está montado / habrá que lanzar un comando mount y  comprobar la linea que contiene 'on / &amp;nbsp;type'.&lt;br /&gt;&lt;br /&gt;&lt;span class="box code" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;span style="color: #666666;"&gt;[&lt;/span&gt;root@virtual01 /&lt;span style="color: #666666;"&gt;]&lt;/span&gt;&lt;span style="color: #408080;"&gt;# mount&lt;/span&gt;/dev/mapper/vg_virtual01-lv_root on / &lt;span style="color: green;"&gt;type&amp;nbsp;&lt;/span&gt;ext4 &lt;span style="color: #666666;"&gt;(&lt;/span&gt;rw&lt;span style="color: #666666;"&gt;)&lt;/span&gt;&lt;br /&gt;proc on /proc &lt;span style="color: green;"&gt;type&amp;nbsp;&lt;/span&gt;proc &lt;span style="color: #666666;"&gt;(&lt;/span&gt;rw&lt;span style="color: #666666;"&gt;)&lt;/span&gt;&lt;br /&gt;sysfs on /sys &lt;span style="color: green;"&gt;type&amp;nbsp;&lt;/span&gt;sysfs &lt;span style="color: #666666;"&gt;(&lt;/span&gt;rw&lt;span style="color: #666666;"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #666666;"&gt;(&lt;/span&gt;...&lt;span style="color: #666666;"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;En el caso del ejemplo, el sistema de ficheros a compactar es &lt;i&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;/dev/mapper/vg_virtual01-lv_root&lt;/span&gt;&amp;nbsp;&lt;/i&gt;, que es un volumen LVM, aunque sería exactamente igual con volúmenes IDE ,&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt; &lt;/span&gt;&lt;i style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;/dev/hdxY&lt;/i&gt; , SCSI o SATA, &lt;i style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;/dev/sdxY&lt;/i&gt; , etc.&amp;nbsp;&lt;/li&gt;&lt;li&gt;A  continuación, habría que montar ese volumen en modo sólo lectura y lanzar el comando zerofill sobre el sistema de ficheros.&lt;br /&gt;&lt;br /&gt;&lt;span class="box code"&gt;&lt;span style="color: #666666; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;[&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;root@virtual01 /&lt;/span&gt;&lt;span style="color: #666666; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;]&lt;/span&gt;&lt;span style="color: #408080; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;# mount -n -o remount,ro -t ext4 /dev/mapper/vg_virtual01-lv_root /&lt;/span&gt;&lt;span style="color: #666666; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt; &lt;br /&gt;[&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;root@virtual01 /&lt;/span&gt;&lt;span style="color: #666666; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;]&lt;/span&gt;&lt;span style="color: #408080;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;# zerofree /dev/mapper/vg_virtual01-lv_root&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Sólo faltaría apagar la máquina&lt;br /&gt;&lt;br /&gt;&lt;span class="box code"&gt;&lt;span style="color: #666666; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;[&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;root@virtual01 /&lt;/span&gt;&lt;span style="color: #666666; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;]&lt;/span&gt;&lt;span style="color: #408080;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;# shutdown -h -P 0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div style="font-family: Verdana,sans-serif; text-align: justify;"&gt;Una vez hecho esto, el sistema está listo para volver a intentar la operación de compactación.&lt;/div&gt;&lt;h2 id="HCompactando...28yII29" style="font-family: Verdana,sans-serif; text-align: justify;"&gt;           Compactando... (y II)&lt;/h2&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="edit_section" style="font-family: Verdana,sans-serif;"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="font-family: Verdana,sans-serif; text-align: justify;"&gt;Ahora si, podemos volver a intentar hacer la operación de compactación&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="box code" style="font-family: Verdana,sans-serif; text-align: justify;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;C:&lt;/span&gt;&lt;span style="color: #bb6622; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace; font-weight: bold;"&gt;\P&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;rogram Files&lt;/span&gt;&lt;span style="color: #bb6622; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace; font-weight: bold;"&gt;\O&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;racle&lt;/span&gt;&lt;span style="color: #bb6622; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace; font-weight: bold;"&gt;\V&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;irtualBox&lt;/span&gt;&lt;span style="color: #bb6622; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace; font-weight: bold;"&gt;\V&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;BoxManage.exe modifyhd &amp;lt;ficheroImagen.vdi&amp;gt; -compact&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%...&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="font-family: Verdana,sans-serif; text-align: justify;"&gt;Si  todo ha ido bien el fichero de imagen de disco tendrá ahora un tamaño  muy similar al tamaño usado dentro del sistema de ficheros, y que se  puede consultar desde el sistema &lt;i&gt;guest&amp;nbsp;&lt;/i&gt;con, por ejemplo para Linux, un &lt;i&gt;df&amp;nbsp;&lt;/i&gt;.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8618841044787531046-485684902900876400?l=www.nocompila.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.nocompila.com/2012/05/compactando-imagenes-de-vm-virtualbox.html</link><author>noreply@blogger.com (Pedro)</author><thr:total>0</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8618841044787531046.post-5860392522427222030</guid><pubDate>Tue, 01 May 2012 18:00:00 +0000</pubDate><atom:updated>2012-05-01T20:22:35.186+02:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>entity framework</category><category domain='http://www.blogger.com/atom/ns#'>.net</category><title>Generando entidades con Entity Framework</title><description>&lt;div class="separator" style="clear: both; text-align: left;"&gt;La oficina es un foco de conversaciones y discusiones (absurdas la mayoría de las veces). El otro día un compañero me comentaba que estaba encantado trabajando con EF. Y yo le pregunté por curiosidad "¿Y cómo generas las entidades?" y su respuesta fue "¿Cómo que cómo?... desde el menú". Mi compañero desconocía que hay varias formas de generar varias formas de generar entidades con EF.&lt;/div&gt;&lt;br /&gt;&lt;b&gt;Data Base First y Model First.&lt;/b&gt;&lt;br /&gt;Estos son las dos formas soportadas por el IDE. Data Base first es la aproximación más utilizada por los usuarios, se modela la base de datos y se utiliza el asistente de entity framework dejando todas las opciones por defecto.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-NFywOM9cHSg/T4XumD2bGMI/AAAAAAAAAAc/73pO2H4p9Ek/s1600/02+GenerateFromDataBase.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="355" src="http://4.bp.blogspot.com/-NFywOM9cHSg/T4XumD2bGMI/AAAAAAAAAAc/73pO2H4p9Ek/s400/02+GenerateFromDataBase.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Model First es muy parecido, desde el asistente del Entity Data Model, seleccionamos Empty model creamos el modelo. El diseñador cuenta con un sasistente para generar el script de la base de datos.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-D_MzNCeRga4/T4XwJkc50LI/AAAAAAAAABE/M7JR9aC5Rns/s1600/07_Empty_Model.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"&gt;&lt;img border="0" height="355" src="http://2.bp.blogspot.com/-D_MzNCeRga4/T4XwJkc50LI/AAAAAAAAABE/M7JR9aC5Rns/s400/07_Empty_Model.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Plain Old CLR Objects (POCOs)&lt;/b&gt;&lt;br /&gt;Una de las características más criticadas de la primera versión de EF fue que las entidades generadas derivaban de la clase &lt;a href="http://msdn.microsoft.com/en-us/library/system.data.objects.dataclasses.entityobject.aspx" target="_blank"&gt;EntityObject&lt;/a&gt;.&lt;br /&gt;Las entidades de se generan mediante plantillas t4, estas plantillas se pueden cambiar o modificar. De esta manera, si nos interesa crear POCOs tan solo debemos indicarlo añadiendo una plantilla al proyecto.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Code First.&lt;/b&gt;&lt;br /&gt;Desde la aparición del EF 4.1 existe una nueva forma de definir el mapeo de las entidades vía código. A esto los amigos de Redmond le han llamado CodeFirst.&lt;br /&gt;Por defecto todo funciona con una convención predefinida.&lt;br /&gt;Pero si queremos trabajar personalizando los nombres o con una base de datos legacy, CodeFirst nos permite definir los mapeos mediante dos formas, vía atributos o mediante&amp;nbsp;código&amp;nbsp;directo.&lt;br /&gt;Supongamos este Modelo de datos:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-GF8enAoPV6E/T6AQyBHgphI/AAAAAAAAACM/SpKBjibkUfg/s1600/ModelEF.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-GF8enAoPV6E/T6AQyBHgphI/AAAAAAAAACM/SpKBjibkUfg/s1600/ModelEF.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;Lo único que tenemos que hacer es crear las clases que necesitemos. En este caso para personalizar el nombre de la tabla o indicar la PK utilizaremos anotaciones&lt;/div&gt;&lt;/div&gt;&lt;pre class="brush:csharp;"&gt;    [Table("Libros")]&lt;br /&gt;    public class Libro&lt;br /&gt;    {&lt;br /&gt;        [Key]&lt;br /&gt;        [Column ("IdLibro")]&lt;br /&gt;        public int Id { get; set; }&lt;br /&gt;        public string Titulo { get; set; }&lt;br /&gt;        public ICollection&amp;lt;Autor&amp;gt; Autores { get; set; }&lt;br /&gt;&lt;br /&gt;        public Libro()&lt;br /&gt;        {&lt;br /&gt;            Autores = new HashSet&amp;lt;Autor&amp;gt;();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    [Table ("Autores")]&lt;br /&gt;    public class Autor&lt;br /&gt;    {&lt;br /&gt;        [Key]&lt;br /&gt;        [Column("IdAutor")]&lt;br /&gt;        public int Id { get; set; }&lt;br /&gt;        public string Nombre { get; set; }&lt;br /&gt;        public ICollection&amp;lt;libro&amp;gt; LibrosEscritos { get; set; }&lt;br /&gt;&lt;br /&gt;        public Autor()&lt;br /&gt;        {&lt;br /&gt;            LibrosEscritos = new HashSet &amp;lt;libro&amp;gt;();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;Ahora lo que debemos generar es el DataBaseContext para que EF sepa qué clases debe mapear&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:csharp;"&gt;    public class LibrosContex : DbContext&lt;br /&gt;    {&lt;br /&gt;        public LibrosContex()&lt;br /&gt;            : base("ConnectionStringName")&lt;br /&gt;        {&lt;br /&gt;&lt;br /&gt;        }&lt;br /&gt;        public DbSet&amp;lt;Libro&amp;gt; Libros { get; set; }&lt;br /&gt;        public DbSet&amp;lt;Autor&amp;gt; Autores { get; set; }&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Desgraciadamente, a fecha de hoy la personalización mediante atributos de EF no permite personalizar el nombre de la tabla intermedia. Esto me permite completar el ejemplo utilizando el API fluido para la configuración del mapeo, indicando el nombre de la tabla intermedia en la relación Many to Many. &lt;br /&gt;&lt;pre class="brush:csharp;"&gt;        protected override void OnModelCreating(DbModelBuilder modelBuilder)&lt;br /&gt;        {&lt;br /&gt;            modelBuilder.Entity&amp;lt;Libro&amp;gt;()&lt;br /&gt;                .HasMany&amp;lt;Autor&amp;gt;(l =&amp;gt; l.Autores)&lt;br /&gt;                .WithMany(a =&amp;gt; a.LibrosEscritos)&lt;br /&gt;                .Map(t =&amp;gt;&lt;br /&gt;                {&lt;br /&gt;                    t.MapLeftKey("IdAutor");&lt;br /&gt;                    t.MapRightKey("IdLibro");&lt;br /&gt;                    t.ToTable("AutoresLibros");&lt;br /&gt;                });&lt;br /&gt;            &lt;br /&gt;        }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;El uso del contexto generado con code first es igual que el generado por los asistentes &lt;br /&gt;&lt;pre class="brush:csharp;"&gt;static void Main(string[] args)&lt;br /&gt;        {&lt;br /&gt;            using (var dbContex = new LibrosContex())&lt;br /&gt;            {&lt;br /&gt;                var libro = new Libro();&lt;br /&gt;                libro.Titulo = "El Hobbit";&lt;br /&gt;&lt;br /&gt;                var autor = new Autor();&lt;br /&gt;                autor.Nombre = "J.R.R. Tolkien";&lt;br /&gt;&lt;br /&gt;                libro.Autores.Add(autor);&lt;br /&gt;                autor.LibrosEscritos.Add(libro);&lt;br /&gt;&lt;br /&gt;                dbContex.Autores.Add(autor);&lt;br /&gt;&lt;br /&gt;                dbContex.SaveChanges();&lt;br /&gt;&lt;br /&gt;                var n = dbContex.Libros.Count&amp;lt;Libro&amp;gt;().ToString();&lt;br /&gt;                Console.WriteLine("Libros en BD: " + n);&lt;br /&gt;                Console.ReadLine();&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Resumiendo&lt;/b&gt;&lt;br /&gt;Entity Framework nos permite elegir varias estrategias de generación de las entidades y los mapeos: Data Base First, Model First y Code First. Además de poder elegir si las entidades son POCOs o no.&lt;br /&gt;Personalmente prefiero code first, aunque sea por la sensación de control o de menos magia que el resto de formas.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8618841044787531046-5860392522427222030?l=www.nocompila.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.nocompila.com/2012/05/formas-de-generar-entidades-con-entity.html</link><author>noreply@blogger.com (Manel)</author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-NFywOM9cHSg/T4XumD2bGMI/AAAAAAAAAAc/73pO2H4p9Ek/s72-c/02+GenerateFromDataBase.png' height='72' width='72'/><thr:total>1</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8618841044787531046.post-8796377959853485758</guid><pubDate>Mon, 23 Apr 2012 18:52:00 +0000</pubDate><atom:updated>2012-04-24T11:16:51.428+02:00</atom:updated><title>JRebel Yell</title><description>&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;Hace cosa de un mes y pico me preguntaron en el chollo si habíamos usado JRebel para desarrollar portlets en Liferay. ¿Jotaqué? ... Y me puse a buscar en el google qué era eso.&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;Resulta que &lt;a href="http://zeroturnaround.com/jrebel/" target="_blank"&gt;JRebel&lt;/a&gt; es un agente Java que evita despliegues en servidores de aplicaciones Java porque permite sustituír código en caliente en toda una manada de servidores de aplicaciones como Tomcat, Jboss, WAS, Jetty, Resin, Netweaver, etc. Y tiene plugins para una buena parte de los grandes IDE para Java: Eclipse, Netbeans, InteliJ, JDeveloper, ...&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://upload.wikimedia.org/wikipedia/en/archive/f/f6/20110630150457%21JRebel_logo.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" src="http://upload.wikimedia.org/wikipedia/en/archive/f/f6/20110630150457%21JRebel_logo.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;span id="goog_1181602400"&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;Soy un asiduo seguidor de Eclipse, y seguro que, como yo, muchos nos hemos encontrado con las limitaciones en el reemplazo de código en caliente que obliga a redesplegar las aplicaciones en el contenedor una y otra vez. Cambiar el cuerpo de método estático, añadir un método, definir una constante, modificar el contexto de Spring, ... nunca más!! JRebel al rescate!! ... o no...&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;JRebel es una buena herramienta con una gran campaña de marketing. ¿Marketing? Si, porque es de PAGO. Y en mayúsculas. &amp;nbsp;Desde la licencia standalone por 130$/año y usuario hasta la flotante con servidor de licencias por 350$/año y usuario. Sí, es cara.&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;Pero ellos lo argumentan diciendo que te puedes ahorrar 10 minutos de despliegues por cada hora de desarrollo.&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;Todo su marketing se enfoca en esto.&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;Y yo no me lo acababa de creer, así que me registré en una trial de un mes y empecé a usarlo para desarrollar portlets en Liferay.&amp;nbsp;Instalé el plugin de JRebel en Eclipse, añadí el plugin de maven al pom.xml , configuré el agente en el Tomcat y empecé a usarlo.&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;La primera impresión fue genial. Magia. Pillaba los cambios. Así de fácil.Yo cambiaba una clase o una JSP de mi portlet y los cambios aparecían al segundo. Genial. Flipa. &lt;i&gt;OyeManelmiraesto&lt;/i&gt;. &lt;i&gt;Nomoredeploys&lt;/i&gt;.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;El entusiasmo sólo dura un par de horas, y los defectos empiezan a notarse. Liferay tarda como el doble en arrancar. Y se ha vuelvo más gordo y lento.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;El primer portlet de prueba era muy básico, pero los proyectos que solemos hacer -normalmente basados en Maven- suelen tener varios módulos con varias librerías, y los cambios sólo se aplicaban si se hacían en el proyecto web.&amp;nbsp;Los cambios en superclases o interfaces tampoco funcionan. Y clases nuevas sólo se detectaban a veces. Evidentemente no funciona con SWT. Ni tampoco con GWT.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;A su favor, sí que se detectan los cambios en las JSP e incluso en el contexto de Spring. Tiene plugins también para Hibernate y JSF - que no he probado - .&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;El plugin se encarga de recordarte un par de veces al día todo el tiempo que has ahorrado en despliegues contabilizando como despliegue cada guardado de un fichero con el servidor levantado. Y sí, en efecto, en una jornada puede contabilizar dos o tres horas. Pero me parece algo exagerado contarlos todos. Sobre todo teniendo en cuenta que hay días que no hago ni un solo despliegue. Sólo programar.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;¿Que se evitan despliegues? Pues claro. Es un ahorro considerable de tiempo. Pero no siempre estamos haciendo corrección de bugs, con lo que las fases de despliegue continuado no son la tónica general.&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;Ya terminó la trial y hoy me llamó un comercial que me puso en un serio aprieto con mis habilidades con el inglés. Sorprendente que me llamasen, si. Y por eso estoy escribiendo esto.&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;Se lo merecen, tienen un buen producto. Aunque no creo que mi empresa lo vaya a comprar. Como puse en el correo que mandé hace un par de semanas a la persona que me preguntó sobre él:&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div style="text-align: justify;"&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;&lt;span class="Apple-style-span" style="font-size: 13px;"&gt;Es una herramienta ÚTIL, PRÁCTICA, especialmente indicada para programadores productivos para los que los despliegues en el servidor suponen una rotura de un ritmo de trabajo alto. Utilizarla requiere EXPERIENCIA en desarrollo para darse cuenta rápidamente de cuándo está desplegando automáticamente y cuándo no. Puede suponer una mejora notable en la productividad de ciertos programadores en determinados tipos de desarrollos.&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: 13px;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;&lt;i&gt;&lt;/i&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif; font-size: 13px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;&lt;i&gt;&lt;/i&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;&lt;span class="Apple-style-span" style="font-size: 13px;"&gt;Y es CARA, cuesta 349 euros por año y programador para entornos empresariales. ¿Vale la pena ese coste para hacerlo extensible a todos los programadores? No lo creo, sobre todo teniendo en cuenta que hay otros factores como un mejor equipo informático o un monitor más grande que mejorarían en mayor medida la productividad de los programadores y que tienen un coste similar o menor.&lt;/span&gt;&lt;/span&gt;&lt;/i&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-size: 13px;"&gt;Eso si, hay una versión SOCIAL no válida para uso comercial y que yo tengo instalado en el Eclipse del equipo de mi casa.&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: 13px;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8618841044787531046-8796377959853485758?l=www.nocompila.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.nocompila.com/2012/04/jrebel-yell.html</link><author>noreply@blogger.com (Pedro)</author><thr:total>2</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8618841044787531046.post-3778200548838279032</guid><pubDate>Mon, 09 Apr 2012 22:00:00 +0000</pubDate><atom:updated>2012-04-10T14:45:28.209+02:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>REST</category><category domain='http://www.blogger.com/atom/ns#'>arquitectura</category><title>Intentando entender REST</title><description>Desde la primera vez que escuché el término servicio REST, siempre lo han utilizado como contrapunto a los servicios web SOAP. Es decir que un servicio REST es una url que recibe peticiones y responde sin usar XML, usando principalmente JSON. Además, si para realizar las peticiones utiliza los verbos http: post, put, delete y get se dice que es RESTful.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;i&gt;"Una mentira repetida mil veces termina siendo verdad"&lt;/i&gt; -&amp;nbsp;&lt;/b&gt;&lt;b&gt;Goebbels&lt;/b&gt;&lt;b&gt;.&lt;/b&gt;&lt;br /&gt;No fue hasta que escuché el podcast &lt;a href="http://www.hanselminutes.com/236/misunderstanding-rest-with-mike-amundsen" target="_blank"&gt;Hanselminutes:&amp;nbsp;Misunderstanding REST with Mike Amundsen&lt;/a&gt;&amp;nbsp;cuando descubrí que REST no era lo que me estaban contando.&lt;br /&gt;REST es un estilo de arquitectura o de diseño informático. No existen unas normas o reglas fijas que definan&amp;nbsp;claramente&amp;nbsp;qué es REST o qué no.&lt;br /&gt;Dentro de este estilo&amp;nbsp;arquitectónico&amp;nbsp;&lt;a href="http://en.wikipedia.org/wiki/Roy_Fielding" target="_blank"&gt;Roy Fielding&lt;/a&gt; es considerado por muchos como el referente. Fielding fue el primero en utilizar el término REST en su trabajo para su doctorado: &lt;i&gt;"Architectural Styles and the Design of Network-based Software Architectures"&lt;/i&gt;. En concreto en el &lt;a href="http://www.ics.uci.edu/%7Efielding/pubs/dissertation/rest_arch_style.htm" target="_blank"&gt;capítulo 5:&amp;nbsp;Representational State Transfer (REST)&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Para explicar este estilo Fielding utiliza HTTP como ejemplo. En el documento se enumeran una serie de condiciones:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Debe ser Cliente/Servidor&lt;/li&gt;&lt;li&gt;La comunicación debe realizarse sin estado, es decir que una&amp;nbsp;petición&amp;nbsp;debe contener toda la información necesaria para que el servidor la procese. Y lo mismo aplicado a la respuesta.&lt;/li&gt;&lt;li&gt;La información debe ser explicita o&amp;nbsp;implícitamente&amp;nbsp;cacheable&lt;/li&gt;&lt;li&gt;Interfaz uniforme:&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Los recursos deben estar identificados (en http los recuros se identifican por la URI)&lt;/li&gt;&lt;li&gt;La&amp;nbsp;manipulación&amp;nbsp;de los&amp;nbsp;recursos&amp;nbsp;se realiza mediante la representación (en http los mensajes indican el tipo de contenido, por ejemplo&amp;nbsp;text/html,&amp;nbsp;application/xmlapplication/xml)&lt;/li&gt;&lt;li&gt;Los mensajes deben ser autodescriptivos: si requiere autenticación, si son cacheable, etc.&lt;/li&gt;&lt;li&gt;Y un último punto que no me quedó muy claro &lt;i&gt;"hypermedia as the engine of application state" &lt;/i&gt;y que desarrolla&amp;nbsp;&lt;a href="http://www.ics.uci.edu/%7Efielding/pubs/dissertation/rest_arch_style.htm#sec_5_2" target="_blank"&gt;&lt;span style="color: #0000ee;"&gt;aquí&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;El sistema debe permitir añadir capas, de tal forma que un cliente no sepa si se está conectando directamente al servidor. Por ejemplo, el sistema debe permitirla implantación de un balanceador de carga.&lt;/li&gt;&lt;li&gt;Código bajo demanda, como el javascript en html, el cliente se&amp;nbsp;descarga&amp;nbsp;el código y luego lo ejecuta. (Esta condición no es obligatoria para que un sistema sea REST.)&lt;/li&gt;&lt;/ul&gt;&lt;b&gt;¿Qué es REST?&lt;/b&gt;&lt;br /&gt;Si he de ser sincero no me ha quedado de todo claro. Lo que sí puedo decir es que REST no es un sistema para hacer CRUDs.&lt;br /&gt;HTTP es el mejor ejemplo de REST y así que un API WEB que siga el estilo REST debe aprovechar al máximo todas las características de HTTP, utilizar metadatos para de las cabeceras para indicar comportamientos, resultados de operaciones, datos de autenticación o de formatos del cuerpo. Por otro lado el cuerpo solo debe utilizarse para intercambiar información.&lt;br /&gt;&lt;br /&gt;La pregunta que yo me hago es: La gente utiliza el termino REST o RESTful para decir que un servicio web no es SOAP, cuando&amp;nbsp;la definición de REST de&amp;nbsp;Fielding&amp;nbsp;es dice otra cosa completamente diferente, ni habla de servicios web. ¿Merece la pena o el esfuerzo explicar que&amp;nbsp;están&amp;nbsp;utilizando el término de forma incorrecta? ¿o como ya está expandida esta acepción del término no merece la pena meterse en a discutir estas cosas si al final nos estamos entendiendo?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8618841044787531046-3778200548838279032?l=www.nocompila.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.nocompila.com/2012/04/intentando-entender-rest.html</link><author>noreply@blogger.com (Manel)</author><thr:total>0</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8618841044787531046.post-3418149739066552454</guid><pubDate>Mon, 20 Feb 2012 07:00:00 +0000</pubDate><atom:updated>2012-02-20T09:06:12.232+01:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>entity framework</category><category domain='http://www.blogger.com/atom/ns#'>.net</category><category domain='http://www.blogger.com/atom/ns#'>nhibernate</category><title>NHibernate y Entity Framework</title><description>A diferencia del mundo Java, donde Hibernate es un estándar de facto, los ORMs en .Net no gozaron de fama hasta la llegada de Entity Framework.&lt;br /&gt;A pesar de la existencia de NHibernate, Microsoft decidió crear un su propio ORM. Y aunque Entity Framework no gozó de buena salud hasta el lanzamiento de su segunda versión (EF4), su popularidad y su uso ha sido muy superior a un producto mucho más maduro como NHibernate.&lt;br /&gt;&lt;br /&gt;Desde mi modesto punto de vista el uso de EF tiene dos peligros:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Las herramientas y el Api de EF son muy intuitivos y permiten a un desarrollador sin experiencia trabajar sin preocuparse de lo que sucede por debajo.&lt;/li&gt;&lt;li&gt;Un desarrollador familiarizado con (N)Hibernate puede pensar que los dos ORM se rigen por los mismos principios y se comportan de manera similar.&lt;/li&gt;&lt;/ul&gt;Cualquiera de los dos casos nos lleva a un escenario, donde el desconocimiento el comportamiento del ORM podría terminar&amp;nbsp;desencovando&amp;nbsp;en &amp;nbsp;una &lt;a href="http://www.nocompila.com/2012/01/abstraccion-aplicaciones-con-pies-de.html"&gt;aplicación con pies de barro&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;El otro día, comiendo con un compañero que está desarrollando una aplicación con EF, hablamos de mis post sobre (N)Hibernate y las diferencias que había entre los dos ORMs tras leer mis post y comparar con su experiencia en el trabajo. Lo cierto es que me sorprendió lo diferente que se pueden llegar a comportar.&lt;br /&gt;&lt;br /&gt;Como ya &lt;a href="http://www.nocompila.com/2012/01/hibernate-y-nhibernate-ii-objetos-y.html" target="_blank"&gt;hemos visto con anterioridad&lt;/a&gt;, NHibernate utiliza una session para comunicarse con la base de datos.&amp;nbsp;Se podría decir que el &lt;a href="http://msdn.microsoft.com/en-us/library/system.data.objects.objectcontext.aspx" target="_blank"&gt;Object Context&lt;/a&gt; de Entity Framework es el equivalente a la session de NHibernate, pero en ocaciones las medias verdades son muy peligrosas.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Conexiones a base de datos&lt;/b&gt;&lt;br /&gt;Abrir y cerrar conexiones contra la base de datos es algo muy costoso.&lt;br /&gt;La sessión de NHibernate&lt;a href="http://nhforge.org/doc/nh/en/index.html#transactions-connection-release" target="_blank"&gt; la abre cuando la necesita y la cierra al terminar una session o al hacer commit en una&amp;nbsp;transacción&lt;/a&gt;. Desgraciadamente el comportamiento por defecto de Entity Framework dista mucho de ser el mismo, segun la &lt;a href="http://msdn.microsoft.com/en-us/library/bb738470.aspx" target="_blank"&gt;msdn&lt;/a&gt;: &lt;i&gt;"By default, the object context manages connections to the database. The object context opens and closes connections as needed. For example, &lt;b&gt;the object context opens connection to execute a query, and then closes the connection when all the result sets have been processed&lt;/b&gt;."&lt;/i&gt;&lt;br /&gt;Es decir que por defecto se abre una&amp;nbsp;conexión&amp;nbsp;por cada consulta que se lanza. Afortunadamente la mayoría de proveedores de ADO.Net incluyen un pool de conexiones, pero de todas formas, es importante ser consciente que a nivel de ADO.Net EF abre y cierra una conexión por defecto.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Recuperando objetos&lt;/b&gt;&lt;br /&gt;&lt;a href="http://www.nocompila.com/2012/01/hibernate-y-nhibernate-ii-objetos-y.html" target="_blank"&gt;En&amp;nbsp;anteriores&amp;nbsp;entradas&lt;/a&gt; ya hemos visto como recupera los objetos NHibernate, la session tiene una caché de primer nivel, donde se almacenan todos los objetos, NHibernate decide si cuando le piden un objeto debe ir a buscarlo a la base de datos o no.&lt;br /&gt;&lt;br /&gt;La política de recuperación de objetos del Objet Context de EF es diferente. Veamos un poco de código:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:csharp;"&gt;    static void Main(string[] args)&lt;br /&gt;    {&lt;br /&gt;        NHibernateEFEntities dbContex = new DBContext ();&lt;br /&gt;&lt;br /&gt;        Pelicula pelicula1 = dbContex.Peliculas.First&amp;lt;pelicula&amp;gt;();&lt;br /&gt;        Console.WriteLine(pelicula1.Titulo);&lt;br /&gt;&lt;br /&gt;        pelicula1.Titulo = "Modificado";&lt;br /&gt;                        &lt;br /&gt;        Pelicula pelicula2 = dbContex.Peliculas&lt;br /&gt;                                .Where(x =&amp;gt; x.IdPelicula == pelicula1.IdPelicula).First&amp;lt;pelicula&amp;gt;();&lt;br /&gt;&lt;br /&gt;        Console.WriteLine("¿son el mismo objeto? {0}", pelicula1.Equals(pelicula2));&lt;br /&gt;&lt;br /&gt;        Console.WriteLine(pelicula2.Titulo);&lt;br /&gt;            &lt;br /&gt;        Console.ReadLine();&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;¿Cómo se comportará EF con este código? Supongamos que la primera película que se recupera de la base de datos es Casablanca. En la línea 8 le cambiamos el nombre por "Modificado" y después la recuperamos de la base de datos. Al ejecutar la línea 12 el programa dice que pelicula1 y pelicula2 son iguales y al ejecutar la línea 14, por consola aparece "Modificado". Parece que esta vez EF y NH se comportan igual, pero consultemos el Log de EF:&lt;br /&gt;&lt;pre class="brush:plain;"&gt;EntityFramework.NHibernateEFEntities Information: 0 : Executing 1: &lt;br /&gt;SELECT TOP (1) [c].[IdPelicula] AS [IdPelicula], [c].[Titulo] AS [Titulo], [c].[IdGenero] AS [IdGenero], [c].[Ano] AS [Ano] FROM [dbo].[Peliculas] AS [c]&lt;br /&gt;&lt;br /&gt;EntityFramework.NHibernateEFEntities Information: 0 : Finished 1 in 00:00:00.0008783: [DbDataReader(IdPelicula:int, Titulo:varchar, IdGenero:int, Ano:int)]&lt;br /&gt;&lt;br /&gt;EntityFramework.NHibernateEFEntities Information: 0 : Executing 2: &lt;br /&gt;SELECT TOP (1) [Extent1].[IdPelicula] AS [IdPelicula], [Extent1].[Titulo] AS [Titulo], [Extent1].[IdGenero] AS [IdGenero], [Extent1].[Ano] AS [Ano] FROM [dbo].[Peliculas] AS [Extent1] WHERE [Extent1].[IdPelicula] = @p__linq__0 { p__linq__0=[Int32,0,Input]1 }&lt;br /&gt;&lt;br /&gt;EntityFramework.NHibernateEFEntities Information: 0 : Finished 2 in 00:00:00.0002692: [DbDataReader(IdPelicula:int, Titulo:varchar, IdGenero:int, Ano:int)]&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;¿Sorprendido? EF ha ejecutado dos consultas, pero en los resultados parece como si supiera que ya tenía en memoria el objeto que se cargó en la primera query. La respuesta de lo que ha pasado está, como casi siempre, está en la &lt;a href="http://msdn.microsoft.com/en-us/library/bb896269.aspx" target="_blank"&gt;msdn&lt;/a&gt;.&lt;br /&gt;EF se comporta de forma muy diferente a NH a la hora de recuperar los objetos en de la base de datos. Lo más importante que debemos saber es que siempre va a realizar la consulta contra la base de datos. Lo que condiciona el comportamiento de EF a la hora de devolver el objeto es el &lt;a href="http://msdn.microsoft.com/en-us/library/system.data.objects.mergeoption.aspx" target="_blank"&gt;MergeOption&lt;/a&gt; de la consulta:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;AppendOnly:&amp;nbsp;&lt;/b&gt;Es la opción por defecto, si una entidad recuperada de una consulta ya existen en el contexto, se devuelve la del contexto y no la recuperada de la base de datos&lt;/li&gt;&lt;li&gt;&lt;b&gt;OverwriteChanges:&lt;/b&gt; Como su propio nombre indica si el objeto existe en el contexto, se sustituye por el que se ha recuperado de la base de datos.&lt;/li&gt;&lt;li&gt;&lt;b&gt;PreserveChanges:&lt;/b&gt;&amp;nbsp;si se recupera de la base de datos una entidad cargada previamente pueden ocurrir dos cosas:&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Si el objeto no había sido modificado, se sustituye por el nuevo&lt;/li&gt;&lt;li&gt;Si se había modificado se mantienen los cambios en el objeto asociado al contexto.&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;&lt;b&gt;NoTracking: &lt;/b&gt;EF no hace seguimiento del objeto.&lt;/li&gt;&lt;/ul&gt;En definitiva EF siempre hace las consultas de la base de datos y según el MergeOption se recuperan unos datos u otros, si a esto le sumamos a que por defecto el ObjectContext abre una conexión por cada consulta. Si el programador que usa EF no conoce estas características (ya sea por desconocimiento o suposiciones incorrectas) puede tener problemas de rendimiento en determinados escenario a la hora de poner un proyecto en producción. Recordad, los ORMs no son magia, y siempre hay una base de datos por debajo.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8618841044787531046-3418149739066552454?l=www.nocompila.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.nocompila.com/2012/02/nhibernate-y-entity-framework.html</link><author>noreply@blogger.com (Manel)</author><thr:total>0</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8618841044787531046.post-8325353647358859609</guid><pubDate>Wed, 25 Jan 2012 23:14:00 +0000</pubDate><atom:updated>2012-01-26T09:10:12.681+01:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>arquitectura</category><title>Repositorio vs DAO</title><description>Una de las partes más importantes de una aplicación, tanto en Java como en .Net, es el acceso a datos. Las dos estrategias más famosas son el DAO y el Repositorio, aunque algunos los confunden, son estrategias diferentes que dan solución al mismo problema.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Patrón DAO&lt;/b&gt;&lt;br /&gt;DAO son las siglas de Data Access Object, pero para entenderlo mejor vayamos a las fuentes &lt;a href="http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html" target="_blank"&gt;J2EE Core Paterns&lt;/a&gt;:&lt;br /&gt;"&lt;i&gt;&lt;b&gt;Use a Data Access Object (DAO) to abstract and encapsulate all access to the data source. The DAO manages the connection with the data source to obtain and store data. &lt;/b&gt;(...)&lt;/i&gt;&lt;br /&gt;&lt;i&gt;The DAO implements the access mechanism required to work with the data source.(...)&amp;nbsp;&lt;/i&gt;&lt;br /&gt;&lt;i&gt;&lt;b&gt;The DAO completely hides the data source implementation details from its clients&lt;/b&gt;.&lt;/i&gt;"&lt;br /&gt;&lt;br /&gt;En román paladino: el DAO es el responsable de componer los datos de sistemas externos, en caso de una base de datos, será el responsable de componer y ejecutar las consultas SQL necesarias para hacer las operaciones. Por ejemplo:&lt;br /&gt;&lt;pre class="brush:csharp;"&gt;    interface IFacturaDAO&lt;br /&gt;    {&lt;br /&gt;        Factura Get(int id);&lt;br /&gt;        void Save(Factura factura);&lt;br /&gt;        void Delete(Factura factura);&lt;br /&gt;&lt;br /&gt;        ICollection&amp;lt;Factura&amp;gt; getFacturasSinCobrar();&lt;br /&gt;    }&lt;/pre&gt;Más o menos este es el ejemplo clásico, un interfaz que nos permite realizar como mínimo las operaciones de un CRUD.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Patrón Repositorio&lt;/b&gt;&lt;br /&gt;Si para el patrón DAO consultamos J2EE Core Patterns, para la definición del repositorio debemos acudir a &lt;a href="http://martinfowler.com/eaaCatalog/repository.html" target="_blank"&gt;Martin&amp;nbsp;Fowler&lt;/a&gt;:&lt;br /&gt;"&lt;i&gt;Mediates between the domain and data mapping layers using a collection-like interface for accessing domain objects&lt;/i&gt;"&lt;br /&gt;&lt;br /&gt;Aunque la definción de los colaboradores de Fowler (Edward Hieatt y Rob Mee) es breve y clara, creo que deja muchos interrogantes abiertos. Únicamente indica que se debe implementar un interfaz similar al de una colección y que por debajo ya se encargará acceder a los datos.&lt;br /&gt;&lt;pre class="brush:csharp;"&gt;    interface IFacturaRepositoy : ICollection&amp;lt;Factura&amp;gt;&lt;br /&gt;    {&lt;br /&gt;        ICollection&amp;lt;Factura&amp;gt; GetFacturasSinCobrar();&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;En este ejemplo, además del interfaz de ICollection, el respositorio de facturas implementa una consulta que recupera las facturas sin cobrar. Pero al implementar ICollection hay que sopesar si se debe implementar el método Clear(), yo personalmente no lo haría ;)&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Las ¿consultas son reglas de negocio? ¿o es parte del acceso a datos?&lt;/b&gt;&lt;br /&gt;Si os fijáis en los ejemplos anteriores, tanto el DAO como el repositorio de factura exponen Este es un debate muy importante que condiciona el desarrollo de la capa de acceso a datos y la implementación de las reglas de negocio.&lt;br /&gt;Utilices DAOs o Repositorios, si crees que las consultas forman parte de las reglas de negocio y quieres mantener la independencia entre negocio y acceso a datos, ¿como puedo escribir las querys, sin usar SQL en la capa de negocio? La solución nos la ofrece otra vez Fowler con el patrón &lt;a href="http://martinfowler.com/eaaCatalog/queryObject.html" target="_blank"&gt;Query Object&lt;/a&gt;: "&lt;i&gt;An object that represents a database query&lt;/i&gt;"&lt;br /&gt;Si crees que las consultas son solo consultas o que programar una implementación de query object es un esfuerzo innecesario, siempre puedes escribir las consultas dentro de tu DAO (incluso dentro del&amp;nbsp;repositorio, estirando un poco la interpretación del patrón).&lt;br /&gt;Algunos de vosotros pensareis, este Query Object se parece mucho a un criteria de Hibernate. Sí, tenéis razón, se podría decir que el api de criteria es una implementación de Query Object. ¿Y por qué no usarlo en la capa de negocio? Porque si usas criteria fuera de la capa de acceso a datos, estas añadiendo una referencia a Hibernate (a un mecanismo de acceso a datos) en tu capa de negocio. Pero de esto hablaremos más tarde en este post (la tercera vía)&lt;br /&gt;En .Net Linq nos permite hacer implementaciones limpias del&amp;nbsp;patrón&amp;nbsp;repositorio. Linq nos permite hacer consultas sobre colecciones IQueriables y está soportado por el framework. Pero ¿exponer IQueriable fuera de nuestro acceso a datos nos permite mantener a nuestras entidades ignorantes de los mecanismos de persistencia? Sí y no.&lt;br /&gt;En teoría sí ya que Linq forma parte del framework, pero en la realidad es que, de esta forma, se limita el número de opciones a disposición del programador: NHibernate, Entity Framework, o algun otro sistema que soporte Linq. Porque el coste de implementar IQueriable en un sistema que utiliza Ado.Net es altísimo y no creo que merezca la pena.&lt;br /&gt;En definitiva se podría decir que se aplican las reglas de negocio en dos momentos de la aplicación:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;al aplicar condiciones para recuperar los datos (recuperar las facturas no pagadas)&amp;nbsp;&lt;/li&gt;&lt;li&gt;Antes de persistir los cambios en la base de datos.&lt;/li&gt;&lt;/ol&gt;Con la palabra "Antes" ya queda claro que es en la capa de negocio donde se deben aplicar las validaciones, cambios de estado, etc. la duda está a la hora de recuperar los datos ¿dentro o fuera del acceso a datos?&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Tercera vía: los ORM ya nos abstraen de la base de datos.&lt;/b&gt;&lt;br /&gt;La gran ventaja de los patrones DAO y repositorio es que abstraen al resto del código de la base de datos, mediante estos mecanismos, si cambia la base de datos no tenemos que tocar la implementación de las reglas de negocio.&lt;br /&gt;Al utilizar ORMs como Hibernate o Entity Framework la abstracción con la base de datos está asegurada. Si ya tenemos una capa de abstracción ¿por qué añadir otra? evitar perder funcionalidad que ofrece el ORM directamente. De esta forma el &lt;a href="http://en.wikipedia.org/wiki/Don%27t_repeat_yourself" target="_blank"&gt;código es más seco (DRY)&lt;/a&gt;, incluso se podría decir que cumple&amp;nbsp;el &lt;a href="http://en.wikipedia.org/wiki/Single_responsibility_principle" target="_blank"&gt;principio de responsabilidad&amp;nbsp;única&lt;/a&gt;, ya que el encargado de guardar el objeto es el ORM. Por último, al no tener DAOs ya no tienes la duda de ¿la consulta es una regla de negocio o forma parte del acceso a datos? al usar el ORM directamente&amp;nbsp;también&amp;nbsp;se usan directamente sus mecanismos de consulta.&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Reflexiones finales&lt;/b&gt;&lt;br /&gt;En una aplicación empresarial, donde es importante tener organizado el código, donde muchas cosas pueden cambiar a petición del cliente y además el equipo estará formado por varias personas, intentaría mantener la capa de acceso a datos completamente aislada, es decir que usaría DAO o Repositorio.&lt;br /&gt;&lt;br /&gt;En .Net dudaría si implementar repositorios exponiendo IQueriables ya que muchos controles del framework, paginan y ordenan estas colecciones.&lt;br /&gt;En Java utilizaría DAOs sin lugar a dudas, no implementaría Query Objects, dejando las consultas en el DAO.&lt;br /&gt;Si estas en una empresa con personas que programan en Java y .Net un DAO con hibernate creo que es la mejor solución.&lt;br /&gt;&lt;br /&gt;El uso directo de un ORM lo dejaría en proyectos pequeños o medianos, con una persona desarrollando y que requieran cambios rápidos. Aunque eso es un riesgo en un entorno empresarial, ya que desaparece esa persona, y lo que para unos es orden, para otros es caos.&lt;br /&gt;&lt;br /&gt;¿Y tu qué opinas? ¿cómo plantearías la estrategia de acceso a datos de una aplicación?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8618841044787531046-8325353647358859609?l=www.nocompila.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.nocompila.com/2012/01/repositrio-vs-dao.html</link><author>noreply@blogger.com (Manel)</author><thr:total>3</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8618841044787531046.post-3209669172706664140</guid><pubDate>Thu, 19 Jan 2012 13:52:00 +0000</pubDate><atom:updated>2012-01-19T14:52:46.707+01:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>real world java</category><title>RWJ. Keep it simple!!</title><description>&lt;div style="font-family: Verdana,sans-serif;"&gt;"La belleza de lo simple"&lt;/div&gt;&lt;br /&gt;&lt;pre class="brush:java;"&gt;boolean orderByAsc = false;&lt;br /&gt;if (orden.equals("asc")) {&lt;br /&gt;    orderByAsc = true;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div style="font-family: Verdana,sans-serif;"&gt;El proyecto que estoy sufriendo está lleno de cosas así. ¿El programador no podría haber hecho algo tan fácil como... ?&lt;/div&gt;&lt;br /&gt;&lt;pre class="brush:java;"&gt;boolean orderByAsc = "asc".equals(orden);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div style="font-family: Verdana,sans-serif;"&gt;Y además, no petaría si orden fuese null.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8618841044787531046-3209669172706664140?l=www.nocompila.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.nocompila.com/2012/01/rwj-keep-it-simple.html</link><author>noreply@blogger.com (Pedro)</author><thr:total>4</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8618841044787531046.post-4863989646081105505</guid><pubDate>Mon, 16 Jan 2012 23:03:00 +0000</pubDate><atom:updated>2012-01-17T00:03:41.488+01:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>base de datos</category><title>La base de datos ¿Fin o Medio?</title><description>Cuando se plantea un desarrollo a medida, una de las primeras preguntas que se hace es: &lt;i&gt;¿Qué base de datos se va a utilizar?&lt;/i&gt;&lt;br /&gt;Aunque creáis que no, tomar la base de datos como un medio o como un fin, condiciona en gran medida el desarrollo del sistema.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Base de datos como Fin&lt;/b&gt;&lt;br /&gt;Si consideramos que la base de datos es la parte más importante de la aplicación, nos preocuparemos de que los datos sean fácilmente legibles. En primer lugar diseñaremos un &lt;a href="http://es.wikipedia.org/wiki/Modelo_de_datos" target="_blank"&gt;modelo de datos&lt;/a&gt;, que posteriormente se traducirá a clases.&lt;br /&gt;La base de datos será el centro del negocio, otras aplicaciones podrían atacar directamente a nuestra base de datos.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Base de datos como Medio&lt;/b&gt;&lt;br /&gt;Desde este punto de vista, la base de datos se considera como un mero sistema para persistir los objetos de negocio de nuestra aplicación&lt;br /&gt;Son los objetos de nuestra aplicación los que realmente ofrecen valor, la consulta de datos de nuestro sistema se debe realizar mediante una capa de servicios que desarrollaremos nosotros, el acceso directo a base de datos podrías dar como resultado lecturas incorrectas.&lt;br /&gt;Adaptaremos el modelo de datos a las necesidades de nuestro código, primando el &lt;a href="http://es.wikipedia.org/wiki/Diagrama_de_clases" target="_blank"&gt;diagrama de clases&lt;/a&gt; sobre modelando los datos.&lt;br /&gt;&lt;br /&gt;En los últimos años, estamos asistiendo al proliferación de las &lt;a href="http://en.wikipedia.org/wiki/Document-oriented_database" target="_blank"&gt;bases de datos documentales&lt;/a&gt;. Esta movimiento se podría considerar como el punto extremo del uso de la base de datos como medio. Ya que de esta forma abandonamos toda la experiencia y el conocimiento que ya existe en las bases de datos relacionales, por un sistema menos estándar.&lt;br /&gt;Lo cierto es que esta moda me recuerda a las &lt;a href="http://en.wikipedia.org/wiki/Object_database" target="_blank"&gt;bases de datos orientadas a objetos&lt;/a&gt;, de las que tanto se hablaba en los 90, mientras que hoy en día parece que nadie se acuerda de ellas.&lt;br /&gt;&lt;br /&gt;Aunque personalmente considero las bases de datos como medio y no como fin, ¿por qué?&lt;br /&gt;Los objetos son los que contienen la información relevante, los objetos no son nadie sin las reglas de negocio a aplicar, que las tengo en las clases, no en la base de datos (nada de procedimientos almacenados, funciones de base datos o trigers). Si alguien quiere acceder a mis datos que me lo pida a través de una capa de integración. Mis datos los toco yo, nadie más.&lt;br /&gt;Eso no&amp;nbsp;significa&amp;nbsp;que no use&amp;nbsp;características&amp;nbsp;de las base de datos, quizás la más importante sea la transaccionalidad, delego en ella la generación de ids.&lt;br /&gt;&lt;br /&gt;Aunque esta aproximación no siempre se puede aplicar, por ejemplo en grandes empresas con bases de datos enormes que alimentan a varias aplicaciones y con un departamento de&amp;nbsp;administración&amp;nbsp;de base de datos. Muchos consideran que trabajar con DBAs es un suplicio por las restricciones que imponen, pero en modelos realmente grandes, con millones de registros, que alguien conozca como se comporta la base de datos y que nos indique como diseñar las tablas para evitar problemas de rendimiento es una&amp;nbsp;ventaja.&lt;br /&gt;&lt;br /&gt;¿Y tu qué opinas? ¿Modelas primero la base de datos y en ella basas tus objetos? ¿Comienzas por el diagrama de clases? ¿o eres de los aventureros que se adentra en las bases de datos documentales?&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8618841044787531046-4863989646081105505?l=www.nocompila.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.nocompila.com/2012/01/la-base-de-datos-fin-o-medio.html</link><author>noreply@blogger.com (Manel)</author><thr:total>3</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8618841044787531046.post-8179752386796737535</guid><pubDate>Tue, 10 Jan 2012 21:17:00 +0000</pubDate><atom:updated>2012-01-11T15:52:59.620+01:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>conocimiento casual</category><title>Abstracción, aplicaciones con pies de barro</title><description>Cuando desarrollamos aplicaciones, utilizamos varios mecanismos de abstracción que nos permiten, entre otras cosas, centrarnos en problemas funcionales, abstrayendonos de ciertos problemas técnicos. Por ejemplo con java o con .net un desarrollador no suele preocuparse por &lt;a href="http://www.nocompila.com/2011/12/rwj-la-memoria-en-la-jvm.html" target="_blank"&gt;la gestión de memoria&lt;/a&gt; porque el recolector de basura de cada plataforma se encarga de eso.&lt;br /&gt;&lt;br /&gt;Los propios lenguajes de programación no mas que abstracciones que permiten comunicarnos de forma &lt;i&gt;sencilla&lt;/i&gt; con las máquinas.&lt;br /&gt;&lt;br /&gt;La abstracción ha permitido que más desarrolladores puedan trabajar, ya que el nivel de conocimiento necesario para hacer el trabajo ha disminuido. Si tuviésemos que trabajar en ensamblador ¿cuanta gente sería capaz de software de calidad?&lt;br /&gt;&lt;br /&gt;&lt;b&gt;La abstracción bien entendida&lt;/b&gt;&lt;br /&gt;Estamos viviendo una época que pasará a los anales de la historia, seguramente en unos años el final del siglo XX y el principio del XXI se conocerá como &lt;i&gt;La revolución informática&lt;/i&gt;. Esta revolución no sería posible sin la abstracción, que permite que mucha gente pueda usar los ordenadores de diferente manera y cada vez con menos conocimiento.&lt;br /&gt;&lt;br /&gt;Pero nunca debemos olvidar qué es lo que estamos usando o de lo qué nos estamos abstrayendo. A pesar de utilizar lenguajes que nos abstraen del comportamiento del micro procesador o del concepto de memoria, no podemos olvidarnos que estos elementos condicionan de forma muy importante el resultado.&lt;br /&gt;&lt;br /&gt;Creo que un desarrollador debe conocer con un cierto nivel de detalle el comportamiento de la última capa de abstracción. Por ejemplo, un desarrollador web debe conocer http, qué pasa cuando se hace un post, qué es una petición ajax, etc.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Aplicaciones con pies de barro&lt;/b&gt;&lt;br /&gt;Es muy importante tener afianzados conocimientos básicos sobre la tecnología que usamos, porque podremos evitar muchos problemas conociendo el contexto en el que trabajamos.&lt;br /&gt;Microsoft creó Asp.Net WebForms como una forma de acercar de forma casi transparente a los desarrolladores de Winforms al entorno web. Con un Visual Studio no necesitas saber http, ni html, ni nada, tan solo arrastrando cajitas y con los asistentes incluidos en el IDE, puedes llegar a hacer aplicaciones de forma relativamente sencilla y rápida.&lt;br /&gt;Por ejemplo al dibujar un botón, tan solo hay que hacer doble click sobre él para abrir una ventana donde pueda condificar la operación necesaria. Esta magia oculta el submit del form, el código funciona y todos felices y contentos.&lt;br /&gt;Creo que ASP.Net WebForms es un gran framework de desarrollo web (a pesar de lo que muchos opinan), pero esta abstracción puede llegar a ser muy peligrosa en malas manos, ya que el desconocimiento de http puede provocar que se comentan errores, provocando problemas de rendimiento y de otra índole.&lt;br /&gt;&lt;br /&gt;En el mundo java el uso de Hibernate es casi el estándar de acceso a datos. Este ORM oculta las comunicaciones de la base de datos, pero el desarrollador nunca debería olvidar que al final lo que se ejecuta son instrucciones SQL. Problemas muy comunes en los ORMs, como el n+1 select, vienen provocados por el desconocimiento de la abstracción.&lt;br /&gt;El acceso a datos es una de las partes más importantes de la aplicación, un error en este punto puede provocar problemas catastróficos muy difíciles de solucionar.&lt;br /&gt;Un ORM no es una tecnología trivial, su uso en cada aplicación debería ser estudiado con mucho cuidado y no usarse a la ligera. Como es un estándar de facto, muchos desarrolladores lo usan sin ser conscientes de lo que hacen.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;i&gt;Conocer la técnica de ORM es fundamental, no es una opción.&lt;/i&gt;&lt;/li&gt;&lt;i&gt;&lt;/i&gt;&lt;li&gt;&lt;i&gt;Nunca olviden que todo termina en una base de datos relacional; empezar con objetos y pensar OO no significa que tengamos que olvidarnos que el data base existe.&lt;/i&gt;&lt;/li&gt;&lt;/ul&gt;Estas dos frases han sido extraídas de un &lt;a href="http://fabiomaulo.blogspot.com/2009/04/empezando-con-nhibernate.html" target="_blank"&gt;post de Fabio Maulo&lt;/a&gt;, donde da consejos a los nuevo usuarios de NHibernate y que pueden aplicarse a los desarrolladores de java.&lt;br /&gt;&lt;br /&gt;Debemos evitar hacer aplicaciones con pies de barro, que se basan en algo que desconocemos, que se usa por costumbre, o porque a otros les ha funcionado, pero que no sabemos lo que hace y que en cualquier momento se puede desmoronar.&amp;nbsp; &lt;br /&gt;&lt;br /&gt;Resumiendo, no debemos basarnos nunca en conocimiento casual, en algo que hace magia pero que no tenemos ni idea de cómo lo hace.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8618841044787531046-8179752386796737535?l=www.nocompila.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.nocompila.com/2012/01/abstraccion-aplicaciones-con-pies-de.html</link><author>noreply@blogger.com (Manel)</author><thr:total>2</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8618841044787531046.post-8910417272404457233</guid><pubDate>Wed, 04 Jan 2012 00:00:00 +0000</pubDate><atom:updated>2012-01-04T01:00:25.159+01:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>java</category><category domain='http://www.blogger.com/atom/ns#'>hibernate</category><category domain='http://www.blogger.com/atom/ns#'>.net</category><category domain='http://www.blogger.com/atom/ns#'>nhibernate</category><title>Hibernate y NHibernate (II) Objetos y sesión</title><description>En &lt;a href="http://www.nocompila.com/2012/01/hibernate-y-nhibernate.html" target="_blank"&gt;entradas anteriores&lt;/a&gt; de NoCompila.com:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&amp;nbsp;Estudiamos como Hibernate y NHibernate es capaz de decidir si debe hacer un Insert o un Update de un objeto. Esta decisión la toma en base al id. Después de escribir el post y revisando la documentación, he descubierto (N)Hibernate también puede utilizar una propiedad version para decidir entre Insert y Update. &lt;/li&gt;&lt;li&gt;Vimos que Hibernate y NHibernate se comportan igual, o prácticamente igual, a la hora de generar insert o updates.&lt;/li&gt;&lt;/ul&gt;Después de unas cuantas charlas con compañeros he decido ampliar el post y hablar sobre la sesión y los objetos, creo que es un tema fundamental para entender el funcionamiento del ORM.&lt;br /&gt;Como lo que vamos a ver son cosas básicas que son iguales en java y en .net solo voy a poner el código en c#, además voy a utilizar unas versiones antiguas (c# 2.0 y NHibernate 2.1) para utilizar métodos y sintaxis lo más comunes y facilite la compresión.&lt;br /&gt;Además vamos a utilizar la clase y el mapeo del post anterior, os los recuerdo:&lt;br /&gt;&lt;pre class="brush:csharp;"&gt;    class Entidad&lt;br /&gt;    {&lt;br /&gt;        private int _id;&lt;br /&gt;        private string _nombre;&lt;br /&gt;&lt;br /&gt;        virtual public int Id&lt;br /&gt;        {&lt;br /&gt;            get { return _id; }&lt;br /&gt;            set { _id = value; }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        virtual public string Nombre&lt;br /&gt;        {&lt;br /&gt;            get {return _nombre;}&lt;br /&gt;            set { _nombre = value; }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public Entidad()&lt;br /&gt;        {&lt;br /&gt;        }&lt;br /&gt;        public Entidad(string nombre)&lt;br /&gt;        {&lt;br /&gt;            Nombre = nombre;&lt;br /&gt;        }&lt;br /&gt;    }&lt;/pre&gt;&lt;pre class="brush:xml;"&gt;&lt;hibernate-mapping assembly="NhibernateSave" namespace="NhibernateSave" xmlns="urn:nhibernate-mapping-2.2"&gt;&lt;br /&gt;  &lt;class name="Entidad" table="Entidades"&gt;&lt;br /&gt;    &lt;id name="Id"&gt;&lt;br /&gt;      &lt;generator class="native"&gt;&lt;/generator&gt;&lt;br /&gt;    &lt;/id&gt;&lt;br /&gt;    &lt;property name="Nombre"&gt;&lt;/property&gt;&lt;br /&gt;  &lt;/class&gt;&lt;br /&gt;&lt;/hibernate-mapping&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;La sesión&lt;/b&gt;&lt;br /&gt;La sesión de (N)Hibernate es, según la documentación del ORM, una implementación del patrón &lt;a href="http://martinfowler.com/eaaCatalog/unitOfWork.html" target="_blank"&gt;Unit of Work&lt;/a&gt;. La sesión controla todos los cambios que se realizan a los objetos que tiene asociados y sabe si tiene que hacer un delete, update o insert.&lt;br /&gt;Además funciona a modo de caché, ya que al hacer las peticiones de base de datos a través de ella esta puede saber si el objeto ya está cargado en memoria sin necesidad de lanzar una select.&lt;br /&gt;&lt;b&gt;¡¡¡OJO!!! a la sesión no se pueden asociar dos objetos del mismo tipo con el mismo id. &lt;/b&gt;de la misma forma que una base de datos no puedes insertar dos registros con la misma pk en la misma tabla. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Estado de los Objetos &lt;/b&gt;&lt;br /&gt;Los objetos en (N)Hibernate pueden estar en tres estados:&lt;br /&gt;&lt;b&gt;Transient&lt;/b&gt;: es un obejto que no está asociado a una sesión de (N)Hibernate. Es decir cuando creamos un objeto con un &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;new&lt;/span&gt;&lt;br /&gt;&lt;b&gt;Persistent&lt;/b&gt;: es un objeto que está asociado a una sesión. Al hacer flush() en la sesión, el estado del objeto se envia a base de datos.&lt;br /&gt;&lt;b&gt;Detached&lt;/b&gt;: es un objeto asociado a una sesión que ya no existe.&lt;br /&gt;para más información &lt;a href="http://docs.jboss.org/hibernate/core/3.3/reference/en/html/objectstate.html#objectstate-overview" target="_blank"&gt;cosultad la documentación oficial&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Asociando objetos a la sesión&lt;/b&gt;&lt;br /&gt;Hacer que un objeto sea Persistent es relativamente sencillo, como es de imaginar el objeto session nos ofrece varios métodos:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;save&lt;/span&gt;: se utiliza cuando se envía un objeto nuevo a la base de datos. Por ejemplo cuando creamos un objeto que no existe en la base de datos. Lo que hace save es ponerle un id al objeto, según la política que esté definida en el mapeo.&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;update&lt;/span&gt;: sirve para asociar un objeto que ya sabemos que existe en base de datos en la sesión. Es decir, a diferencia de save, update no le asigna id al objeto.&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;SaveOrUpdate&lt;/span&gt;: lo vimos en el post anterior, asocial al objeto a la sesión, decidiendo si usar save o update&lt;/li&gt;&lt;/ul&gt;Veamos un ejemplo:&lt;br /&gt;&lt;pre class="brush:csharp;"&gt;            Configuration cfg = new Configuration();&lt;br /&gt;            cfg.Configure();&lt;br /&gt;            ISessionFactory sf = cfg.BuildSessionFactory();&lt;br /&gt;            ISession session = sf.OpenSession();&lt;br /&gt;&lt;br /&gt;            Entidad e1 = new Entidad("UNO"); //creamos un objeto transient&lt;br /&gt;            session.Save(e1); //el objeto se vuelve Persistent&lt;br /&gt;&lt;br /&gt;            session.Flush();//Se lanza un Insert en la base de datos&lt;br /&gt;            session.Close(); //e1 pasa a ser detached &lt;br /&gt;&lt;br /&gt;            session = sf.OpenSession();&lt;br /&gt;&lt;br /&gt;            Entidad e2 = new Entidad(); //se crea el objeto transient&lt;br /&gt;            e2.Id = e1.Id;&lt;br /&gt;            e2.Nombre = "DOS";&lt;br /&gt;&lt;br /&gt;            session.Update(e2); // e2 se vuelve Persistent&lt;br /&gt;&lt;br /&gt;            e2.Nombre = "TRES";&lt;br /&gt;&lt;br /&gt;            session.Flush ();&lt;br /&gt;            session.Close(); //e2 pasa a ser detached&lt;br /&gt;&lt;br /&gt;            sf.Close();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;¿Cuantas querys se lanzan contra la base de datos?¿y en qué momento?&lt;br /&gt;Se lanzan tan solo dos querys contra la base de datos, un insert y un update:&lt;br /&gt;&lt;pre class="brush:sql;"&gt;    INSERT &lt;br /&gt;    INTO&lt;br /&gt;        Entidades&lt;br /&gt;        (Nombre) &lt;br /&gt;    VALUES&lt;br /&gt;        (@p0);&lt;br /&gt;    select&lt;br /&gt;        SCOPE_IDENTITY();&lt;br /&gt;    @p0 = 'UNO'&lt;br /&gt;&lt;br /&gt;    UPDATE&lt;br /&gt;        Entidades &lt;br /&gt;    SET&lt;br /&gt;        Nombre = @p0 &lt;br /&gt;    WHERE&lt;br /&gt;        Id = @p1;&lt;br /&gt;    @p0 = 'TRES', @p1 = 1032&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;El insert se lanza en la primera sesión que creamos, en la línea 7 al hacer el &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;save&lt;/span&gt;. Lo hace aqui porque el generador de id que está definido en el mapeo es native, esto significa que le tiene que pedir a la base de datos el id. Únicamente por esta razón lanza el insert en esa línea. Si subiésemos definido el generador como &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;guid&lt;/span&gt; el ORM le asignaría como id un &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;new System.Guid()&lt;/span&gt; y no ejecutaría el insert en ese momento.&lt;br /&gt;&lt;br /&gt;El update se lanza en la linea 22, al hacer el flush de la segunda sesión.&lt;br /&gt;Es muy importante no confundir session.save y session.update con operaciones de base de datos. Os recuerdo que la sesión es la encargada de realizar las comunicaciones con la base de datos, save y update solo pasan a persistent un objeto. Fijaos en el update del log, el valor de nombre es TRES, pero en el código se hizo update con el nombre valiendo DOS. Esto es porque update solo asoció el objeto a la sesión. Es la sesión al hacer flush la que envía los cambios que tiene controlados a la base de datos.&lt;br /&gt;&lt;br /&gt;La sesión tiene una propiedad llamada flushMode donde se define la política de flush. Yo recomendaría hacer un flush manual antes de cerrar la sesión para evitarnos sorpresas inesperadas.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Lock&lt;/span&gt;: solo se debe usar con objetos detached y sirve para atachearlos a la sesión. ¿entonces cual es la diferencia con update? Cuando se hace update de un objeto detached hibernate siempre lanzará un update a la base de datos (salvo que en mapping se le marque con select-before-update, entonces lanzará una select antes para saber si debe actualizar). Es decir si no sabemos si el objeto ha cambiado desde que se cerró la sesión podemos usar Update, si sabemos que no cambio podemos usar lock.&lt;/li&gt;&lt;/ul&gt;&lt;pre class="brush:csharp"&gt;            Configuration cfg = new Configuration();&lt;br /&gt;            cfg.Configure();&lt;br /&gt;            ISessionFactory sf = cfg.BuildSessionFactory();&lt;br /&gt;            ISession session = sf.OpenSession();&lt;br /&gt;&lt;br /&gt;            Entidad e1 = new Entidad("UNO"); &lt;br /&gt;            Entidad e2 = new Entidad("ALFA");&lt;br /&gt;            session.Save(e1); &lt;br /&gt;            session.Save(e2);&lt;br /&gt;&lt;br /&gt;            session.Flush();&lt;br /&gt;            session.Close();  &lt;br /&gt;&lt;br /&gt;            session = sf.OpenSession();&lt;br /&gt;&lt;br /&gt;            e2.Nombre = "BETA";&lt;br /&gt;&lt;br /&gt;            session.Update(e1); &lt;br /&gt;            session.Lock(e2, LockMode.None);&lt;br /&gt;&lt;br /&gt;            session.Flush ();&lt;br /&gt;            session.Close();&lt;br /&gt;&lt;br /&gt;            session = sf.OpenSession();&lt;br /&gt;&lt;br /&gt;            session.Lock(e2, LockMode.None);&lt;br /&gt;            e2.Nombre = "GAMMA";&lt;br /&gt;&lt;br /&gt;            session.Flush();&lt;br /&gt;            session.Close();&lt;br /&gt;&lt;br /&gt;            sf.Close();&lt;br /&gt;&lt;/pre&gt;En las líneas 7 y 8 lanza los inserts correspondientes para cada objeto.&lt;br /&gt;En el flush de la linea 21 lanza un update para actualizar el objeto e1, esta operación no sería necesaria porque el objeto no cambió, pero al reasociarlo con update se lanza una actualización contra la base de datos. Fijaos que en la linea 16 hemos actualizado el nombre de la e2, pero al estar detached ninguna sessión capturó el cambio, así que en la linea 21 no se nos lanza un update para este objeto.&lt;br /&gt;En el flush de la linea 29 se lanza un update de la e2 ya que esta vez sí que hemos cambiado el nombre del objeto cuando estaba asociado a la sesión.&lt;br /&gt;Aquí tenéis el log con las querys: &lt;br /&gt;&lt;pre class="brush:sql"&gt;    INSERT &lt;br /&gt;    INTO&lt;br /&gt;        Entidades&lt;br /&gt;        (Nombre) &lt;br /&gt;    VALUES&lt;br /&gt;        (@p0);&lt;br /&gt;    select&lt;br /&gt;        SCOPE_IDENTITY();&lt;br /&gt;    @p0 = 'UNO'&lt;br /&gt;&lt;br /&gt;    INSERT &lt;br /&gt;    INTO&lt;br /&gt;        Entidades&lt;br /&gt;        (Nombre) &lt;br /&gt;    VALUES&lt;br /&gt;        (@p0);&lt;br /&gt;    select&lt;br /&gt;        SCOPE_IDENTITY();&lt;br /&gt;    @p0 = 'ALFA'&lt;br /&gt;&lt;br /&gt;--Flush Línea 21&lt;br /&gt;    UPDATE&lt;br /&gt;        Entidades &lt;br /&gt;    SET&lt;br /&gt;        Nombre = @p0 &lt;br /&gt;    WHERE&lt;br /&gt;        Id = @p1;&lt;br /&gt;    @p0 = 'UNO', @p1 = 1047&lt;br /&gt;&lt;br /&gt; --Flush Línea 29&lt;br /&gt;    UPDATE&lt;br /&gt;        Entidades &lt;br /&gt;    SET&lt;br /&gt;        Nombre = @p0 &lt;br /&gt;    WHERE&lt;br /&gt;        Id = @p1;&lt;br /&gt;    @p0 = 'GAMMA', @p1 = 1048&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Merge&lt;/span&gt;: Quizás lo describía mejor su antiguo nombre SaveOrUpdateCopy, es decir, busca en la sesión y en base de datos el objeto, si existe lo machaca con el que lo pasamos y devuelve una instancia del objeto asociado a la sesión. Con este método evitamos que la sesión lance un error al intentar asociar un objeto con un id ya asociado a la sesión. &lt;/li&gt;&lt;/ul&gt;No sé si ha quedado claro, veamos un ejemplo &lt;br /&gt;&lt;pre class="brush:csharp"&gt;            Configuration cfg = new Configuration();&lt;br /&gt;            cfg.Configure();&lt;br /&gt;            ISessionFactory sf = cfg.BuildSessionFactory();&lt;br /&gt;            ISession session = sf.OpenSession();&lt;br /&gt;&lt;br /&gt;            Entidad e1 = new Entidad("UNO"); &lt;br /&gt;            Entidad e2 = new Entidad("ALFA");&lt;br /&gt;            e1 = (Entidad)session.Merge(e1);&lt;br /&gt;            e2.Id = e1.Id; &lt;br /&gt;            e2 = (Entidad)session.Merge(e2);&lt;br /&gt;&lt;br /&gt;            session.Flush();&lt;br /&gt;            session.Close();  &lt;br /&gt;&lt;br /&gt;            session = sf.OpenSession();&lt;br /&gt;&lt;br /&gt;            e2.Nombre = "BETA";&lt;br /&gt;&lt;br /&gt;            session.Merge(e2); &lt;br /&gt;            &lt;br /&gt;            session.Flush ();&lt;br /&gt;            session.Close();&lt;br /&gt;&lt;br /&gt;            sf.Close();&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;En este caso el merge de la línea 8 provoca un insert, ya que como pasamos a la sesión un objeto sin Id (N)Hibernate va a la base de datos para calcularla. En la línea 10 se machaca el objeto de sesión e1, con el e2 (porque tienen el mismo id) pero no se lanza ninguna query. En la línea 12 en el flush de la primera sesión se realiza un update que cambia el nombre de UNO a ALFA en la base de datos. En la línea 19 en el merge de una nueva sesión se lanza una select, ya que el objeto que se le pasa no está en la sesión y tiene que ir a la base de datos a buscarlo. En la línea 21, el flush provoca un update actualizando el Nombre a BETA &lt;br /&gt;&lt;pre class="brush:sql"&gt;--Línea 8, Merge&lt;br /&gt;    INSERT &lt;br /&gt;    INTO&lt;br /&gt;        Entidades&lt;br /&gt;        (Nombre) &lt;br /&gt;    VALUES&lt;br /&gt;        (@p0);&lt;br /&gt;    select&lt;br /&gt;        SCOPE_IDENTITY();&lt;br /&gt;    @p0 = 'UNO'&lt;br /&gt;&lt;br /&gt;--Línea 12, Flush&lt;br /&gt;    UPDATE&lt;br /&gt;        Entidades &lt;br /&gt;    SET&lt;br /&gt;        Nombre = @p0 &lt;br /&gt;    WHERE&lt;br /&gt;        Id = @p1;&lt;br /&gt;    @p0 = 'ALFA', @p1 = 1053&lt;br /&gt;&lt;br /&gt;--Línea 19, Merge&lt;br /&gt;    SELECT&lt;br /&gt;        entidad0_.Id as Id0_0_,&lt;br /&gt;        entidad0_.Nombre as Nombre0_0_ &lt;br /&gt;    FROM&lt;br /&gt;        Entidades entidad0_ &lt;br /&gt;    WHERE&lt;br /&gt;        entidad0_.Id=@p0;&lt;br /&gt;    @p0 = 1053&lt;br /&gt;&lt;br /&gt;--Línea 21, Flush&lt;br /&gt;    UPDATE&lt;br /&gt;        Entidades &lt;br /&gt;    SET&lt;br /&gt;        Nombre = @p0 &lt;br /&gt;    WHERE&lt;br /&gt;        Id = @p1;&lt;br /&gt;    @p0 = 'BETA', @p1 = 1053&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Espero que con esto quede claro como se comporta NHibernate, está claro que esto no cubre todos los casos, pero creo que es interesante y necesario conocer como se comportan los objetos con la sesión y como se pasan de transient a persistent y a detached.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8618841044787531046-8910417272404457233?l=www.nocompila.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.nocompila.com/2012/01/hibernate-y-nhibernate-ii-objetos-y.html</link><author>noreply@blogger.com (Manel)</author><thr:total>0</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8618841044787531046.post-7320195419723102596</guid><pubDate>Mon, 02 Jan 2012 22:42:00 +0000</pubDate><atom:updated>2012-01-03T09:32:45.151+01:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>java</category><category domain='http://www.blogger.com/atom/ns#'>hibernate</category><category domain='http://www.blogger.com/atom/ns#'>.net</category><category domain='http://www.blogger.com/atom/ns#'>nhibernate</category><title>Hibernate y NHibernate</title><description>El otro día en la oficina estaba hablando con un compañero sobre &lt;a href="http://www.hibernate.org/" target="_blank"&gt;Hibernate&lt;/a&gt;. Este compañero me comentaba que debía asociar a la sesión objetos antes de guardarlos. Según me explicaba, al hacer un new de un objeto y guardarlo directamente con Hibernate, el ORM daba fallos en algunos escenarios pudiendo lanzar &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;inserts&lt;/span&gt; cuando debería hacer &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;updates&lt;/span&gt; o al revés (no me acuerdo).&lt;br /&gt;Desgraciadamente para mí, nunca he podido utilizar &lt;a href="http://www.nhforge.org/" target="_blank"&gt;NHibernate&lt;/a&gt; en un proyecto real de producción, pero estaba seguro que el comportamiento que me describía no se daba en .Net y siendo proyectos hermanos, supuse que el comportamiento sería igual en Hibernate.&lt;br /&gt;Este compañero de la oficina es difícil de convencer, así que programé una mini aplicación de consola en c# para demostrarle como se comportaba el ORM.&lt;br /&gt;&lt;br /&gt;Primero hice una clase Entidad:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:csharp;"&gt;    class Entidad&lt;br /&gt;    {&lt;br /&gt;        private int _id;&lt;br /&gt;        private string _nombre;&lt;br /&gt;&lt;br /&gt;        virtual public int Id&lt;br /&gt;        {&lt;br /&gt;            get { return _id; }&lt;br /&gt;            set { _id = value; }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        virtual public string Nombre&lt;br /&gt;        {&lt;br /&gt;            get {return _nombre;}&lt;br /&gt;            set { _nombre = value; }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public Entidad()&lt;br /&gt;        {&lt;br /&gt;        }&lt;br /&gt;        public Entidad(string nombre)&lt;br /&gt;        {&lt;br /&gt;            Nombre = nombre;&lt;br /&gt;        }&lt;br /&gt; &lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Depues añadí el Mapping de NHibernate&lt;br /&gt;&lt;pre class="brush:xml;"&gt;&lt;hibernate-mapping assembly="NhibernateSave" namespace="NhibernateSave" xmlns="urn:nhibernate-mapping-2.2"&gt;&lt;br /&gt;  &lt;class name="Entidad" table="Entidades"&gt;&lt;br /&gt;    &lt;id name="Id"&gt;&lt;br /&gt;      &lt;generator class="native"&gt;&lt;/generator&gt;&lt;br /&gt;    &lt;/id&gt;&lt;br /&gt;    &lt;property name="Nombre"&gt;&lt;/property&gt;&lt;br /&gt;  &lt;/class&gt;&lt;br /&gt;&lt;/hibernate-mapping&gt;&lt;br /&gt;&lt;/pre&gt;Y por último el código del programa. Tened en cuenta que es una aplicación de NHibernate donde se trabaja directamente con &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;session&lt;/span&gt;, es decir, que este código &lt;b&gt;no es una buena referencia&lt;/b&gt; para escribir una aplicación profesional.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:csharp;"&gt;    class Program&lt;br /&gt;    {&lt;br /&gt;        static void Main(string[] args)&lt;br /&gt;        {&lt;br /&gt;            Configuration cfg = new Configuration();&lt;br /&gt;            cfg.Configure();&lt;br /&gt;            ISessionFactory sf = cfg.BuildSessionFactory();&lt;br /&gt;            ISession session = sf.OpenSession();&lt;br /&gt;&lt;br /&gt;            Entidad entidad = new Entidad("PRUEBA");&lt;br /&gt;            session.SaveOrUpdate(entidad);&lt;br /&gt;&lt;br /&gt;            session.Flush();&lt;br /&gt;            session.Close();&lt;br /&gt;&lt;br /&gt;            session = sf.OpenSession();&lt;br /&gt;            Entidad entidad2 = new Entidad();&lt;br /&gt;            entidad2.Id = entidad.Id;&lt;br /&gt;            entidad2.Nombre = "MODIFICADO";&lt;br /&gt;&lt;br /&gt;            session.SaveOrUpdate(entidad2);&lt;br /&gt;&lt;br /&gt;            session.Flush();&lt;br /&gt;            session.Close();&lt;br /&gt;&lt;br /&gt;            sf.Close();      &lt;br /&gt;        }&lt;br /&gt;    } &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Como podéis ver, el código es muy simple. Se crea una entidad y se llama directamente al método &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;SaveOrUpdate&lt;/span&gt; y cerramos la sesión. Si os fijáis en el mapeo de Entidad podéis ver que el generador del id es &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;native&lt;/span&gt;, esto significa que la base de datos es la responsable de asignarle un ID. En mi caso (un SQL Server) la columna Id de la tabla Entidades está definida como &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;identity&lt;/span&gt; (autoincremental). Mirando la consulta de base de datos que ejecuta NHibernate podemos ver lo siguiente:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:sql;"&gt;INSERT &lt;br /&gt;    INTO&lt;br /&gt;        Entidades&lt;br /&gt;        (Nombre) &lt;br /&gt;    VALUES&lt;br /&gt;        (@p0);&lt;br /&gt;    select&lt;br /&gt;        SCOPE_IDENTITY();&lt;br /&gt;    @p0 = 'PRUEBA'&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Podemos ver claramente como NHibernate no envía el Id y deja a la base de datos asignarle un valor, despés de insertar el registro, recupera el id haciendo &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;select SCOPE_IDENTITY&lt;/span&gt;&lt;br /&gt;Después de eso se cierra la sesión y se crea otra nueva, además se crea una nueva entidad que copia las propiedades Id y Nombre del objeto anterior y se vuelve a guardar. Esta vez nos encontramos con un objeto creado fuera de la sesión de NHibernate, pero que representa a un registro existente en base de datos. ¿Qué hará el ORM cuando tenga que almacenarlo en la base de datos? ¿Sabrá hacerlo? Esto es lo que hace NHibernate:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:sql;"&gt;UPDATE&lt;br /&gt;        Entidades &lt;br /&gt;    SET&lt;br /&gt;        Nombre = @p0 &lt;br /&gt;    WHERE&lt;br /&gt;        Id = @p1;&lt;br /&gt;    @p0 = 'MODIFICADO', @p1 = 1&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;NHibernate ha sabido que tenía que hacer un &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;update&lt;/span&gt; aunque el objeto no llegó de la sesión. ¿Cómo lo hace? Muy sencillo, en el mapeo se indica que el tipo de &lt;a href="http://nhforge.org/doc/nh/en/index.html#mapping-declaration-id-generator" target="_blank"&gt;generador de id&lt;/a&gt; es &lt;a href="http://nhforge.org/doc/nh/en/index.html#mapping-declaration-id-generator" target="_blank"&gt;native&lt;/a&gt;, lo que significa que será la base de datos la responsable de asignar id. En el primer caso, como el objeto no tenía id, hizo un &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;insert&lt;/span&gt;, en el segundo como ya tenía id hizo un &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;update&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Como comenté anteriormente, mi compañero no es fácil de convencer, y no le gustó mi explicación. Así que intentó ponerla en duda. Me pidió que quitase el identity a la base de datos y que asignase el id de forma manual.&lt;br /&gt;No voy a volver a copiar y pegar todo el código, porque es el mismo, solo os indicaré que puse esta línea antes del primer &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;SaveOrUpdate()&lt;/span&gt; esto:&lt;br /&gt;&lt;pre class="brush:csharp;"&gt;    entidad.Id = 1024;&lt;br /&gt;&lt;/pre&gt;además modifiqué el mapping &lt;br /&gt;&lt;pre class="brush:xml;"&gt;  &lt;class name="Entidad" table="Entidades"&gt;&lt;br /&gt;    &lt;id name="Id"&gt;&lt;br /&gt;      &lt;generator class="assigned"&gt;&lt;/generator&gt;&lt;br /&gt;    &lt;/id&gt;&lt;br /&gt;    &lt;property name="Nombre"&gt;&lt;/property&gt;&lt;br /&gt;  &lt;/class&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Esta vez, al asignar de forma manual el id, NHibernate no sabe si tiene que lanzar un &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;update&lt;/span&gt; o un &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;insert&lt;/span&gt; ¿Cómo pensais que se comportaría al guardar el primer objeto? &lt;br /&gt;&lt;pre class="brush:sql"&gt;    SELECT&lt;br /&gt;        entidad_.Id,&lt;br /&gt;        entidad_.Nombre as Nombre0_ &lt;br /&gt;    FROM&lt;br /&gt;        Entidades entidad_ &lt;br /&gt;    WHERE&lt;br /&gt;        entidad_.Id=@p0;&lt;br /&gt;    @p0 = 1024&lt;br /&gt;&lt;br /&gt;    INSERT &lt;br /&gt;    INTO&lt;br /&gt;        Entidades&lt;br /&gt;        (Nombre, Id) &lt;br /&gt;    VALUES&lt;br /&gt;        (@p0, @p1);&lt;br /&gt;    @p0 = 'PRUEBA', @p1 = 1024&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Como podemos ver NHibernate no hace magia, lanza un &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;select&lt;/span&gt; contra el Id para saber si el objeto existe en base de datos. Como no existe lanza un &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;insert&lt;/span&gt;. Con el segundo objeto hace lo mismo: &lt;br /&gt;&lt;pre class="brush:sql"&gt;    SELECT&lt;br /&gt;        entidad_.Id,&lt;br /&gt;        entidad_.Nombre as Nombre0_ &lt;br /&gt;    FROM&lt;br /&gt;        Entidades entidad_ &lt;br /&gt;    WHERE&lt;br /&gt;        entidad_.Id=@p0;&lt;br /&gt;    @p0 = 1024&lt;br /&gt;&lt;br /&gt;    UPDATE&lt;br /&gt;        Entidades &lt;br /&gt;    SET&lt;br /&gt;        Nombre = @p0 &lt;br /&gt;    WHERE&lt;br /&gt;        Id = @p1;&lt;br /&gt;    @p0 = 'MODIFICADO', @p1 = 1024&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Esta vez, &lt;span style="font-family: &amp;quot;Calibri&amp;quot;,&amp;quot;sans-serif&amp;quot;; font-size: 11pt; line-height: 115%;"&gt;después &lt;/span&gt; de comprobar que el objeto existe en base de datos mediante otro &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;select&lt;/span&gt;, el ORM decide lanzar un &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;update&lt;/span&gt;.&lt;br /&gt;Después de todo esto pesaréis que la discusión quedó zanjada, y que mi compañero confía en mi explicación... pues de eso nada. Mi compañero ahora sostiene que Hibernate y NHibernate se comportan de forma diferente, lo que me obliga a hacer el mismo programa en java para demostrarle que Hibernate y NHibernate (al menos en este caso) se comportan de la misma forma.&lt;br /&gt;Así que volví a crear la clase entidad (perdonad si me cargo alguna convención de java, al final, el 90% de mi tiempo lo paso picando vb.net): &lt;br /&gt;&lt;pre class="brush:java"&gt;public class Entidad {&lt;br /&gt; private Integer id;&lt;br /&gt; private String Nombre;&lt;br /&gt; public void setId(Integer id) {&lt;br /&gt;  this.id = id;&lt;br /&gt; }&lt;br /&gt; public Integer getId() {&lt;br /&gt;  return id;&lt;br /&gt; }&lt;br /&gt; public void setNombre(String nombre) {&lt;br /&gt;  Nombre = nombre;&lt;br /&gt; }&lt;br /&gt; public String getNombre() {&lt;br /&gt;  return Nombre;&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;El mapeo de Hibernate es prácticamente igual que el de NHibernate y este post ya es demasiado largo, así que os copio el código del programa de consola: &lt;br /&gt;&lt;pre class="brush:java"&gt; public static void main(String[] args) {&lt;br /&gt;  // TODO Auto-generated method stub&lt;br /&gt;  Configuration conf = new Configuration().configure();&lt;br /&gt;  SessionFactory sf = conf.buildSessionFactory();&lt;br /&gt;  Session session = sf.openSession();&lt;br /&gt;  &lt;br /&gt;  Entidad entidad = new Entidad();&lt;br /&gt;  entidad.setNombre("Prueba");&lt;br /&gt;   &lt;br /&gt;          session.saveOrUpdate(entidad);&lt;br /&gt;&lt;br /&gt;          session.flush();&lt;br /&gt;          session.close();&lt;br /&gt;         &lt;br /&gt;          session = sf.openSession();&lt;br /&gt;          Entidad entidad2 = new Entidad();&lt;br /&gt;          entidad2.setId(entidad.getId());&lt;br /&gt;          entidad2.setNombre("MODIFICADO");&lt;br /&gt;&lt;br /&gt;          session.saveOrUpdate(entidad2);&lt;br /&gt;&lt;br /&gt;          session.flush();&lt;br /&gt;          session.close();&lt;br /&gt;&lt;br /&gt;          sf.close();&lt;br /&gt;  &lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Como podeis ver en java he hecho lo mismo que en c#. La primera vez que se ejecuta el código la base de datos tiene configurado el campo id con &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;identity&lt;/span&gt; y las consultas que lanza Hibernate son: &lt;br /&gt;&lt;pre class="brush:sql;"&gt;insert into Entidades (Nombre) values (?)&lt;br /&gt;update Entidades set Nombre=? where Id=?&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Y al quitar el &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;identity&lt;/span&gt; y poner &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;assigned&lt;/span&gt; en el mapeo la aplicación genera estas consultas: &lt;br /&gt;&lt;pre class="brush:sql;"&gt;select entidad_.Id, entidad_.Nombre as Nombre0_ from Entidades entidad_ where entidad_.Id=?&lt;br /&gt;insert into Entidades (Nombre, Id) values (?, ?)&lt;br /&gt;select entidad_.Id, entidad_.Nombre as Nombre0_ from Entidades entidad_ where entidad_.Id=?&lt;br /&gt;update Entidades set Nombre=? where Id=?&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;En resumen, y obviando la diferencia de formatos de logs entre Hibernate y su hermano de .NET, los dos ORMs se comportan de la misma forma. (N)Hibernate utiliza el ID para saber si un objeto está en base de datos y saber si tiene que lanzar un update o un insert.&lt;br /&gt;Como nota curiosa he de mencionar que para el ejemplo de java he usado Hibernate 4 y me he llevado una sorpresa al descubrir que &lt;a href="http://docs.jboss.org/hibernate/core/4.0/javadocs/org/hibernate/cfg/Configuration.html#buildSessionFactory%28%29" target="_blank"&gt;buildSessionFactory() está deprecado&lt;/a&gt; pero esto no afectó a mi prueba de concepto.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8618841044787531046-7320195419723102596?l=www.nocompila.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.nocompila.com/2012/01/hibernate-y-nhibernate.html</link><author>noreply@blogger.com (Manel)</author><thr:total>2</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8618841044787531046.post-745570962492898675</guid><pubDate>Tue, 20 Dec 2011 00:35:00 +0000</pubDate><atom:updated>2011-12-20T02:07:29.329+01:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>java</category><category domain='http://www.blogger.com/atom/ns#'>real world java</category><title>RWJ. La memoria en la JVM</title><description>&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;Aunque muchas veces se nos olvida, la JVM es un proceso del sistema operativo como otro cualquiera. Si, si. Lo que leéis. Y como en el resto de procesos, la memoria está dividida en tres regiones : &amp;nbsp;el &lt;i&gt;stack&lt;/i&gt;, el &lt;i&gt;heap &lt;/i&gt;y&lt;i&gt;&amp;nbsp;&lt;/i&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;el&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;&lt;i&gt;code segment&lt;/i&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;el &lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;&lt;i&gt;stack&lt;/i&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;&amp;nbsp;es la zona de memoria donde se almacenan los parámetros que se pasan a una función en una llamada, las variables locales e información de retorno. Cada vez que se llama a una función desde dentro de otra, se &lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;&lt;i&gt;apilan &lt;/i&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;los parámetros de la nueva función y sus variables hasta que se haga &lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;&lt;i&gt;return&lt;/i&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;el &lt;i&gt;heap&lt;/i&gt;&amp;nbsp;es el área de memoria en el que "se hacen los &lt;i&gt;malloc() "&amp;nbsp;&lt;/i&gt;. En él se guardan las estructuras de datos permanentes en memoria. Y en los lenguajes orientados a objetos, se crean los objetos. Y si se usa mucho, acaba por llenarse.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;el&amp;nbsp;&lt;i&gt;code segment&lt;/i&gt;&amp;nbsp;es la zona de memoria donde reside el código del proceso. En el caso de la JVM, es la parte del código que no está programado en Java. Es decir, el core&amp;nbsp;&lt;i&gt;nativo&amp;nbsp;&lt;/i&gt;de la JVM.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;Como comentaba, la JVM es un proceso como otro cualquiera. Y la &lt;i&gt;gran idea &lt;/i&gt;que tuvo Sun fue hacer un proceso que ejecutase procesos. Y esos &lt;i&gt;pseudoprocesos&lt;/i&gt;&amp;nbsp;están escritos en &lt;i&gt;bytecode, &lt;/i&gt;una especie de código máquina para JVM, independiente de la plataforma sobre la que se ejecute la JVM.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;Como tuvieron tiempo para pensárselo, hicieron las cosas a conciencia: los programas Java se compilan a &amp;nbsp;&lt;i&gt;bytecode&lt;/i&gt;&amp;nbsp;común y se ejecutan en la JVM -específica por sistema operativo- . La &lt;i&gt;orientación a objetos&lt;/i&gt;&amp;nbsp; está muy presente en todo el diseño del lenguaje y, como no, en el de la propia JVM. La máquina virtual ofrece mecanismos para liberar la memoria de los objetos obsoletos, llamado &lt;i&gt;garbage collector&lt;/i&gt;. Y el propio código de los programas Java forma parte del paradigma objetual.&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;&lt;b&gt;El área de memoria de los procesos de la JVM tiene un diseño propio&lt;/b&gt;, muy parecido al de los sistemas operativos, pero diseñado para facilitar el&amp;nbsp;&lt;i&gt;garbage collecting:&lt;/i&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;el &lt;i&gt;stack&lt;/i&gt;, con el mismo funcionamiento comentado antes&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;el &lt;i&gt;heap&lt;/i&gt;, en el que se crean todos los objetos utilizados, y sobre los que posteriormente se hará recolección de basura, con dos partes :&lt;/span&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;&lt;i&gt;young generation: &lt;/i&gt;en el que se crean los nuevos objetos (&lt;i&gt;eden&lt;/i&gt;) y con dos &lt;i&gt;survival spaces&lt;/i&gt;&amp;nbsp;por los que van pasando los objetos antes de llegar a la&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;&lt;i&gt;tenured (old) generation, &lt;/i&gt;en el que acaban&amp;nbsp;los objetos persistentes a los &lt;i&gt;gc.&lt;/i&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;el &lt;i&gt;permanent generation space , &lt;/i&gt;equivalente al &lt;i&gt;code segment&lt;/i&gt;. En él se va cargando la información de las clases y métodos utilizados. La memoria usada en este espacio no se libera jamás, y hará falta más espacio cuantas más clases utilice el proceso.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;A nivel de implementación de sistema operativo, tanto el &lt;i&gt;heap &lt;/i&gt;como el &lt;i&gt;permgen space &lt;/i&gt;se guardan en el &lt;i&gt;heap &lt;/i&gt;del proceso JVM, aunque cuando hablamos de Java, solemos decir que &lt;i&gt;el permgen space no es parte del heap.&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;Por cuestiones de diseño y seguridad, la memoria máxima que el proceso de la JVM va a utilizar se define en el momento de arrancarla, y no es posible aumentarla. ¿Cómo? Con las siguientes opciones :&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;-Xms64m&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt; , que indica que el tamaño del heap reservado al arrancar la JVM será de 64 megas.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;-Xmx1024m&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;, que limita a 1024 megas el tamaño máximo de heap reservable.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;-XXMaxPermSize=128m&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt; , limita a 128 megas el tamaño máximo de la permanent generation.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;La memoria máxima reservada por defecto para la JVM de Sun es &lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;-Xmx64m&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt; . Pero estos y otros muchos &lt;a href="http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html"&gt;parámetros son configurables&lt;/a&gt;&amp;nbsp;.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;Leído todo esto, es posible que empecéis a distinguir los diferentes errores de memoria de la JVM&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;java.lang.StackOverflowError .&amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;Error de desbordamiento de pila, que ocurre cuando se apilan tantas llamadas a funciones que se salen de su espacio de memoria ( normalmente con llamadas recursivas infinitas )&amp;nbsp;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;java.lang.OutOfMemoryError : heap space&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt; . Ocurre cuando el heap se llena por completo y el &lt;i&gt;gc&lt;/i&gt;&amp;nbsp;no es capaz de liberar espacio. Puede deberse a memory leaks o a que nuestro programa necesita más memoria.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;&lt;span class="Apple-style-span" style="font-family: Times;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;java.lang.OutOfMemoryError : PermGen space failure&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Times;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;&amp;nbsp;. Cuando el &lt;i&gt;permgen space &lt;/i&gt;se llena a tope. Puede deberse a que no hay memoria suficiente para cargar todas las clases que llamamos (¿¿nos cargamos todo apache commons?? ) o a memory leaks en classloaders que recargan clases en caliente pero no liberan bien la memoria de las anteriores.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;&lt;div style="font-family: Times;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;Y en cuanto al tema del&amp;nbsp;&lt;i&gt;garbage collector,&amp;nbsp;&lt;/i&gt;yo creo que&lt;i&gt;&amp;nbsp;&lt;/i&gt;se merece una entrada propia. ¿Se echa de menos algún dibujo en el artículo?&lt;/span&gt;&lt;/div&gt;&lt;div style="font-family: Times;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8618841044787531046-745570962492898675?l=www.nocompila.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.nocompila.com/2011/12/rwj-la-memoria-en-la-jvm.html</link><author>noreply@blogger.com (Pedro)</author><thr:total>1</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8618841044787531046.post-2380130589518899998</guid><pubDate>Tue, 13 Dec 2011 20:19:00 +0000</pubDate><atom:updated>2011-12-13T21:25:25.058+01:00</atom:updated><title>Comprando chollos</title><description>&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;Soy de los que les gustan los libros. Me parece mucho más fácil aprender de un libro que de blogs o de una &lt;i&gt;plataforma de formación online&lt;/i&gt;. Pero lo malo es que los libros técnicos cuestan una pasta.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;Yo creo que a día de hoy ya sabemos todos que los libros salen muuuy baratos en amazon (sobre todo en el de US). Lo malo son los sablazos que nos pegan por los portes.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;Pues resulta que &lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;&lt;a href="http://www.play.com/"&gt;play.com&lt;/a&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;&amp;nbsp;no sólo vende juegos y camisetas. También vende libros, y aunque no es la repera como amazon, lo que si que tiene son chollazos en la parte de segunda mano - libros muy baratos y portes gratis - .&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;La semana pasada me compré estos libros y ... ya los tengo en casa:&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;&lt;a href="http://www.play.com/Books/Books/4-/666423/-/Product.html"&gt;The Unified Modeling Language&lt;/a&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt; por 4,76 €&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;&lt;a href="http://www.play.com/Books/Books/4-/2009926/-/Product.html"&gt;Refactoring in Large Software Projects&lt;/a&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt; por 4,30 €&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;&lt;a href="http://www.play.com/Books/Books/4-/1039497/-/Product.html"&gt;Bitter java&lt;/a&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt; por 5,30 €&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;&lt;a href="http://www.play.com/Books/Books/4-/843499/-/Product.html"&gt;Beyond Java&lt;/a&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;&amp;nbsp;por 2,90 €&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;Y todo con portes gratis y enviados en paquetes separados para evitar grandes males.&amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;Por eso os aconsejo consultar de vez en cuando los &lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;&lt;a href="http://www.play.com/Books/Books/-/123/180/3-/Refine.html?searchfilters=c%7B133%7D+&amp;amp;ob=4"&gt;libros de programación ordenados por precio&lt;/a&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;&amp;nbsp;.&lt;/span&gt;&lt;/div&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8618841044787531046-2380130589518899998?l=www.nocompila.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.nocompila.com/2011/12/comprando-chollos.html</link><author>noreply@blogger.com (Pedro)</author><thr:total>0</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8618841044787531046.post-4989067331643797364</guid><pubDate>Wed, 02 Nov 2011 07:00:00 +0000</pubDate><atom:updated>2011-11-02T11:10:44.239+01:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>web</category><title>Consejos de Coco</title><description>&lt;span id="internal-source-marker_0.9644765965791382" style="background-color: transparent; font-size: 11pt; text-decoration: none; vertical-align: baseline;"&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;Hola niños, soy Coco y hoy voy a enseñaros la diferencia entre servidor y cliente en aplicaciones web.&lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&lt;span class="Apple-style-span" style="font-size: 15px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="background-color: transparent; font-size: 11pt; text-decoration: none; vertical-align: baseline;"&gt;El cliente es un navegador,  y hay de muuuuuuuuuuchas clases. Algunos tienen una E azul muy gorda y todo el mundo habla mal de ellos. Otros tienen un zorro enroscado.  Dicen que los hackers usan uno con una O roja. Google también tiene el suyo y puede hacer que se esconda debajo de la E azul.&lt;/span&gt;&lt;br /&gt;&lt;span style="background-color: transparent; font-size: 11pt; text-decoration: none; vertical-align: baseline;"&gt;Pero todos hacen dos cosas pintar HTML y ejecutar Javascript.&lt;/span&gt;&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&lt;span class="Apple-style-span" style="font-size: 15px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="background-color: transparent; font-size: 11pt; text-decoration: none; vertical-align: baseline;"&gt;El servidor es un ordenador muy grande que hace muchas cosas, es muy potente y puede hacer casi de todo: poner pelis y música, imprimir, hacer ficheros, leer bases de datos,… el límite lo pone tu imaginación.&lt;/span&gt;&lt;br /&gt;&lt;span style="background-color: transparent; font-size: 11pt; text-decoration: none; vertical-align: baseline;"&gt;Pero el pobre servidor está solito, no tiene usuarios que jueguen con él, así que cuando programes para él haz que hable con los navegadores, que tenga algo de compañía.&lt;/span&gt;&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&lt;span style="background-color: transparent; font-size: 11pt; text-decoration: none; vertical-align: baseline;"&gt;Si pones al servidor a hacer cosas solito se pone muy triste. Lo peor que puedes hacerle es obligarle a mostrar un cuadro de diálogo, en esos casos el servidor esperará a que alguien venga y le responda, pero lo triste es que nadie llegará. Algunas veces la depresión es tan grande que el servidor dejará todo esperando la respuesta.&lt;/span&gt;&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&lt;span class="Apple-style-span" style="font-size: 15px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="background-color: transparent; font-size: 11pt; text-decoration: none; vertical-align: baseline;"&gt;Para hablar con la gente el servidor puede mandar html y javascript o incluso ficheros (eso los muy listos) al navegador, donde lo mostrará todo muy bonito (en unos más que en otros), preguntarle cosas con cuadros de dialogo o guadar pdfs...&lt;/span&gt;&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&lt;span class="Apple-style-span" style="font-size: 15px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="background-color: transparent; font-size: 11pt; text-decoration: none; vertical-align: baseline;"&gt;Ya sabeis niños, el amigo del servidor es el navegador, haz que hable con él, y no lo pongas a hablar solo, que se deprime.&lt;/span&gt;&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;&lt;span style="background-color: transparent; font-size: 11pt; text-decoration: none; vertical-align: baseline;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="background-color: transparent; font-size: 11pt; text-decoration: none; vertical-align: baseline;"&gt;¡¡¡Y COMO VUELVA A VER UN MSGBOX EN UNA DLL COMIENZO A CORTAR MANOS!!! &amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8618841044787531046-4989067331643797364?l=www.nocompila.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.nocompila.com/2011/11/hola-ninos-soy-coco-y-hoy-voy-ensenaros.html</link><author>noreply@blogger.com (Manel)</author><thr:total>3</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8618841044787531046.post-3665909607795185604</guid><pubDate>Mon, 31 Oct 2011 07:00:00 +0000</pubDate><atom:updated>2011-10-31T08:00:01.561+01:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>powershell</category><category domain='http://www.blogger.com/atom/ns#'>windows</category><title>Grep en Windows</title><description>Esta tarde hablando con un compañero le pregunté si se podía crear un logger para log4net en el que solo sacase los WARN de una clase. Me comentó que él haría un &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;grep &lt;/span&gt;y que eso era una de las razones por las cuales le gustaban más los sistemas tipo Linux/UNIX. Entonces recordé que en windows tambien podemos hacer cosas de este tipo y le comenté que con &lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;findstring&lt;/span&gt; se podía hacerse. He de reconocer que no suelo pensar en línea de comandos. Hace años que dejé eso (desde que no tengo que editar autoexec.bat y el config.sys para ejecutar&amp;nbsp;según&amp;nbsp;que juegos).&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Me gustan las ventanas y no lo niego&lt;/b&gt;&lt;br /&gt;Creo que los sistemas de ventanas son muy cómodos, no solo a nivel usuario. Para realizar tareas de administración me gusta tener una ventana donde vea todas las opciones y poder editar. Me resulta infinitamente más cómodo que tener que leerme un fichero de script y esperar que las opciones que necesite y que no estén configuradas vengan en una linea comentada.&lt;br /&gt;Aunque reconozco que para ciertas operaciones por lotes la linea de comandos está muy bien y que debería pensar más en eso de lo que suelo hacer.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Linea de comandos en Windows.&lt;/b&gt;&lt;br /&gt;Aunque parezca mentira hay linea de comandos en windows, y a fata de una hay dos: El command (para mi MS-DOS aunque no lo sea) y el Powershell.&lt;br /&gt;Powershell es mucho más pontente que la consola de MS-DOS. Fue desarrollado por Mircrosoft para contentar a los administradores de windows que echaban de menos una linea de comando&amp;nbsp;ponente, como la de UNIX. Se lanzó en el 2003 y actualmente se distribuye con los sistemas operativos, tanto de servidor (Server 2008) como de escritorio (Windows 7).&lt;br /&gt;La nueva política de Microsoft intenta que todos sus productos tengan soporte powershell para que los administradores puedan hacer las mismas operaciones tanto desde ventanas como desde linea de comandos, así que sqlserver trae sus scripts de powershell, exchange server también, etc.&lt;br /&gt;Por ejemplo si instalas el Server Core de Windows 2008 Server, se teiene que hacer todo desde la línea de comandos.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Punto negro de powershell&lt;/b&gt;&lt;br /&gt;Powershell tiene una carencia  importante: No hay una instruccion equivalente a tail -f en UNIX. Lo más  parecido es get-content -wait, pero no funciona todo lo bien que sería  necesario. Afortunadamente la comunidad de ususarios han generado  herramientas para suplir esta carencia. Esperoemos que los chicos de  Redmond añadan soporte oficial en próximas actualizaciones.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Ya está bien de tanto coñazo ¿y lo del grep como va?&lt;/b&gt;&lt;br /&gt;Para filtrar lineas de fichero en MS-DOS existe la instrucción findstr y para volcar a un fichero cualquier salida de comando utilizamos &amp;gt; así que para hacer el filtro que necesitaba en el log solo tenía que hacer:&lt;br /&gt;&lt;div style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;findstr WARN aplicacion.log &amp;gt; logfiltrado.log&lt;/div&gt;&lt;br /&gt;En powershell se haría concatenando tres comandos: get-content, select-string y out-file, los comandos en powershell se concatenan con pipes:&lt;br /&gt;&lt;div style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;get-content aplicacion.log | select-string WARN | out-file logfiltrado.log&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8618841044787531046-3665909607795185604?l=www.nocompila.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.nocompila.com/2011/10/grep-en-windows.html</link><author>noreply@blogger.com (Manel)</author><thr:total>3</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8618841044787531046.post-3427704098382211246</guid><pubDate>Tue, 25 Oct 2011 16:30:00 +0000</pubDate><atom:updated>2011-10-25T18:30:03.327+02:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>.net</category><category domain='http://www.blogger.com/atom/ns#'>svn</category><title>Visual Studio, SVN y conflictos.</title><description>Mi compañero Pedro ha comenzado una &lt;a href="http://www.nocompila.com/search/label/real%20world%20java" target="_blank"&gt;serie de post sobre desarrollo en Java&lt;/a&gt;. En sus primeras entregas ha comenzado por uno de los puntos básicos del desarrollo en equipo: el repositorio de código fuente (o sistema de control de versiones). Como bien indica, uno de los más utilizados actualmente es el Subversion (SVN). Este sistema se comporta muy bien con grandes equipos y al permitir trabajar de forma desconectada hace que sea unos de los sistemas más utilizados por los proyectos Open Source.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Conflictos en SVN&lt;/b&gt;&lt;br /&gt;De todas formas, si se trabaja con Visual Studio, se deben tener ciertas precauciones, debido a la forma de gestionar los conflictos que tiene SVN. Se detecta un conflicto cuando dos o más programadores realizan cambios en las mismas líneas de un fichero a la vez. Para indicar los conflictos SVN modifica el fichero de trabajo, marcándolos de esta forma:&lt;br /&gt;&lt;pre&gt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt; fichero&lt;br /&gt;    modificaciones del usuario&lt;br /&gt;=======&lt;br /&gt;    última versión subida al SVN&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; revisión&lt;/pre&gt;Además añade tres ficheros:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;fichero.ext.mine: &lt;/b&gt;la copia del fichero de trabajo que usaba el usuario antes de lanzar el &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;update&lt;/span&gt;.&lt;/li&gt;&lt;li&gt;&lt;b&gt;fichero.ext.rOLDREV: &lt;/b&gt; una copia de la versión del fichero antes de que el usuario comenzase a modificarlo.&lt;/li&gt;&lt;li&gt;&lt;b&gt;fichero.ext.rNEWREV: &lt;/b&gt; una copia de la última versión del fichero en el momento de detectar el conflicto.&lt;/li&gt;&lt;/ul&gt;&lt;b&gt;Visual Studio y SVN&lt;/b&gt; &lt;br /&gt;Visual Studio utiliza ficheros índice que le indican con qué trabajar:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;fichero.sln:&lt;/b&gt; define la solución, contiene todos los proyectos, sus rutas y el modo de acceder a ellos.&lt;/li&gt;&lt;li&gt;&lt;b&gt;fichero.csproj o fichero.vbproj:&lt;/b&gt; De forma similar a los sln, los ficheros de proyecto (proyectos vb o c#) contienen una lista con todos los ficheros que utilizan (código fuente, referencias a librerías, ...)&lt;/li&gt;&lt;/ul&gt;Los conflictos con estos ficheros pueden producirse inconscientemente por parte de los programadores, ya que al añadir un proyecto a la solución, o un fichero a un proyecto, el Visual Studio modifica los sln y los proj. Estas modificaciones, si se producen en paralelo, seguramente provocarán conflictos en y el SVN marcará estos en los ficheros. Con estos ficheros marcados el Visual Studio no es capaz de leerlos, por lo tanto, desaparecerían los proyectos o incluso la solución, del explorador de proyectos (lo que provocaría un buen susto a más de uno).&lt;br /&gt;Para solucionar este problema, tan solo hay que salir del entorno de desarrollo y resolver el conflicto, depués volver a cargar los proyectos o la solución que provocaba el error.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Soluciones&lt;/b&gt;&lt;br /&gt;SVN es un sistema muy extendido. A pesar de sus problemillas con Visual Studio, muchos de los proyectos Open Source de .NET lo utilizan.&lt;br /&gt;Una de las estrategias más utilizadas para evitar estos problemas es ignorar los cambios en los ficheros solución y de proyecto para que el SVN no gestione sus actualizaciones. Cada vez que se realice un update, se deben buscar los proyectos, ficheros y referencias añadidas para incluirlas de forma manual, para que únicamente el Visual Studio gestione los ficheros índice. Aunque esto no parezca la mejor solución es una de las más extendidas.&lt;br /&gt;Si todos los miembros del equipo de desarrollo están en la misma oficina, podemos utilizar otra estrategia. Siempre que un desarrollador añada un fichero, este lo sube y avisa al resto del equipo para que actualicen, de esta forma no se producirán conflictos en los ficheros índice.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Conclusiones&lt;/b&gt;&lt;br /&gt;El SVN es un buen sistema para trabajo en equipo, aunque no lo recomendaría para utilizar con el Visual Studio. Sobre todo en las fases iniciales de un proyecto, donde varias personas suben ficheros en paralelo. En proyectos de mantenimiento, donde el desarrollo principal ya se ha finalizado y las tareas más habituales son editar ficheros (no borrarlos o añadirlos) podría ser una solución aceptable.&lt;br /&gt;Existen soluciones alternativas al SVN, tanto de pago (Team Foundation, Source Safe) como gratuitas (como Mercurial o Git). Microsoft parece que apuesta por Mercurial, al menos eso parece indicar el soporte a este sistema por parte de &lt;a href="http://www.codeplex.com/" target="_blank"&gt;www.codeplex.com&lt;/a&gt;, el portal que aloja proyectos Open Souce que gestiona Microsoft.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8618841044787531046-3427704098382211246?l=www.nocompila.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.nocompila.com/2011/10/visual-studio-svn-y-conflictos.html</link><author>noreply@blogger.com (Manel)</author><thr:total>1</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8618841044787531046.post-8525909496811256678</guid><pubDate>Mon, 24 Oct 2011 06:00:00 +0000</pubDate><atom:updated>2011-10-24T21:51:16.816+02:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>javascript</category><category domain='http://www.blogger.com/atom/ns#'>ajax</category><title>Javascript, JSON y las fechas</title><description>&lt;p&gt;En estos últimos años se ha puesto muy de moda el uso de JSON con Ajax para el envío de datos entre la página web y el servidor. Pero si consultamos la &lt;a href="http://www.json.org/json-es.html" target="_blank"&gt;definición de JSON&lt;/a&gt; podemos comprobar que este formato no tiene soporte para fechas.&lt;/p&gt;&lt;p&gt;&lt;b&gt;Formato fecha en JSON&lt;/b&gt;  &lt;p&gt;Los desarrolladores que implementan los serializadores de JSON deben decidir que estrategia utilizar. Por otro lado, los que explotan servicios de terceros que envían fechas por JSON deben conocer son enviados, así que es recomendable solicitar la documentación donde se explique en qué formato se envían los datos.&lt;p&gt;Como programador en .NET sé que el serializador viene por defecto con el framework envía las fechas en un string con el siguiente formato: &lt;span style="font-family:courier new;"&gt;/Date(1319130612160)/&lt;/span&gt;&lt;/p&gt;&lt;p&gt;La cifra que va entre paréntesis indica el número de milisegundos transcurridos desde el 01/01/1970. Este formato es el mismo que usa javascript para crear sus fechas. Si nos fijamos, podemos ver como el serializador de Microsoft ya nos da hecho el constructor del &lt;span style="font-family:courier new;"&gt;Date&lt;/span&gt; en javascript, así que para convertir a fecha tan solo hay que quitar las barras al string y poner un new delante. Se podría codificar una funcion parecida a esta:  &lt;pre class="brush: jscript;"&gt;&lt;br /&gt;        function DateDeserialize(dateStr) {&lt;br /&gt;            return eval('new ' + dateStr.replace(/\//g, '') + ';');&lt;br /&gt;        }&lt;/pre&gt;&lt;p&gt;&lt;b&gt;Formateando Fechas en Javascript&lt;/b&gt;&lt;/p&gt;&lt;p&gt;Desgraciadamente Javascript no tiene funciones para formatear las fechas. La única solución es programar nuestras propias funciones. La otra forma que conozco de hacerlo es utilizando JQueryUI, un conjunto de plugins oficial de JQuery, pero para esto, el proyecto web debería estar ya usando eso. No incluiría unas librerías que pesan tanto en un proyecto solo para solucionar este problema. &lt;p&gt;El datepicker es plugin que se utiliza para decorar inputs para incluir un calendario. Además tiene un método llamado formatDate con el que podemos formatear las fechas con una sintaxis que resulta familiar para la mayoría de los programadores, por ejemplo: &lt;span style="font-family:courier new;"&gt;$.datepicker.formatDate('dd-mm-yy', fecha)&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;Conclusión&lt;/b&gt;  &lt;p&gt;Siempre que se pueda, hay que evitar trabar con fechas en javascript. Todo ese trabajo es mucho mejor realizarlo en el lado del servidor. Es más rápido y se dispone de un api mucho más completo (lo que evita muchos problemas).&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8618841044787531046-8525909496811256678?l=www.nocompila.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.nocompila.com/2011/10/javascript-json-y-las-fechas.html</link><author>noreply@blogger.com (Manel)</author><thr:total>0</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8618841044787531046.post-5111750775541531381</guid><pubDate>Thu, 20 Oct 2011 22:30:00 +0000</pubDate><atom:updated>2011-10-21T01:30:45.834+02:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>java</category><title>Reemplazando con expresiones regulares</title><description>&lt;div style="font-family: Verdana,sans-serif;"&gt;En ciertas ocasiones he necesitado reemplazar todas las apariciones de una cierta expresión dentro de una cadena. La última vez era necesario hacer una transformación de URLs dentro del HTML de una página obtenido con un httpclient . Una buena parte de los programadores Java con los que he trabajado conocen la función &lt;a href="http://download.oracle.com/javase/6/docs/api/java/lang/String.html#replaceAll%28java.lang.String,%20java.lang.String%29"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;replaceAll()&lt;/span&gt;&lt;/a&gt; de &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;java.lang.String&lt;/span&gt; , pero casi nunca la he visto aplicada a expresiones regulares. &lt;/div&gt;&lt;div style="font-family: Verdana,sans-serif;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: Verdana,sans-serif;"&gt;Por ejemplo, imaginemos que queremos modificar todas las apariciones de &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;/display/xxxx/yyyy&lt;/span&gt; como atributo en el HTML y sustituirlas por &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;http://nocompila.com:8081/display?space=&lt;i&gt;xxxx&lt;/i&gt;&amp;amp;page=&lt;i&gt;yyyy&lt;/i&gt;&lt;/span&gt;&lt;i&gt; &lt;/i&gt;, en donde &lt;i&gt;xxxx &lt;/i&gt;e &lt;i&gt;yyyy &lt;/i&gt;puede ser cualquier expresión alfanumérica.  &lt;/div&gt;&lt;div style="font-family: Verdana,sans-serif;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: Verdana,sans-serif;"&gt;Para hacer esto he llegado a ver de todo, hasta construcciones del árbol DOM del html, búsqueda de nodos con atributos href con recorridos en profundidad (nada de XPath), obtención de su valor como String, tokenización, recomposición y asignación de nuevo a través del API DOM. &lt;/div&gt;&lt;div style="font-family: Verdana,sans-serif;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: Verdana,sans-serif;"&gt;Pues con expresiones regulares es muy fácil, sólo hay que hacer uso de sus &lt;i&gt;matching groups&lt;/i&gt; : dentro de una expresión regular es posible utilizar paréntesis para envolver ciertas partes de la expresión. Y se puede usar el contenido de los paréntesis en la expresión de sustitución referenciándolo con &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;$i&lt;/span&gt; , siendo i la posición del grupo de paréntesis en la expresión y comenzando a numerarlos en 1. &lt;/div&gt;&lt;br /&gt;&lt;div style="font-family: Verdana,sans-serif;"&gt;Para nuestro ejemplo se haría &lt;/div&gt;&lt;br /&gt;&lt;pre class="brush:java;"&gt;String html = // obtener html de la url&lt;br /&gt;&lt;br /&gt;String newHtml = html.replaceAll(  &lt;br /&gt;                     "=\"/display/([^/]+)/([^\"]+)\""&lt;br /&gt;                   , "=\"http://localhost:8081/display?space=$1&amp;amp;page=$2\"");&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div style="font-family: Verdana,sans-serif;"&gt;Fácil, ¿verdad? . El único inconveniente es coger soltura con las expresiones regulares, pero el esfuerzo suele valer la pena.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8618841044787531046-5111750775541531381?l=www.nocompila.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.nocompila.com/2011/10/reemplazando-con-expresiones-regulares.html</link><author>noreply@blogger.com (Pedro)</author><thr:total>1</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8618841044787531046.post-5079290562359549952</guid><pubDate>Thu, 20 Oct 2011 14:50:00 +0000</pubDate><atom:updated>2011-10-20T16:52:40.689+02:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>java</category><category domain='http://www.blogger.com/atom/ns#'>humor</category><title>Festival del Humor (IV)</title><description>Hola, os dejo una muestra de código que nos llega desde el otro lado del charco :&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:java;"&gt;public class CertificadoConSaldo implements Serializable {&lt;br /&gt;&lt;br /&gt; private static final long serialVersionUID = 1L;&lt;br /&gt;&lt;br /&gt; private transient CertificadoIVR certificadoIVR ;&lt;br /&gt;&lt;br /&gt; private Cuenta[] cuentas;&lt;br /&gt;&lt;br /&gt; /**&lt;br /&gt;  * Constructor default&lt;br /&gt;  */&lt;br /&gt; public CertificadoConSaldo() {&lt;br /&gt;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; /**&lt;br /&gt;  * Implementa un adapatador que convierte un CertificadoConSaldoIvrCEVO en&lt;br /&gt;  * un certificadoConSaldo para mostrar en el XML&lt;br /&gt;  */&lt;br /&gt; public CertificadoConSaldo(CertificadoConSaldoIvrCEVO vo) {&lt;br /&gt;  certificadoConSaldoIvrCEVO = vo;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public Cuenta[] getCuentas() {&lt;br /&gt;&lt;br /&gt;  if (certificadoIVR.getCuentas() != null) {&lt;br /&gt;&lt;br /&gt;   List listaCuentas = certificadoIVR.getCuentas();&lt;br /&gt;   cuentas = new Cuenta[listaCuentas.size()];&lt;br /&gt;&lt;br /&gt;   int index = 0;&lt;br /&gt;   for (Iterator iterator = listaCuentas.iterator(); iterator&lt;br /&gt;     .hasNext();) {&lt;br /&gt;&lt;br /&gt;    CuentaIvrVO cuentaIvrVO = (CuentaIvrVO) iterator.next();&lt;br /&gt;    cuentas[index++] = new Cuenta(cuentaIvrVO);&lt;br /&gt;   }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  return cuentas;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public void setCuentas(Cuenta[] cuentas) {&lt;br /&gt;  this.cuentas = cuentas;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Lo peor es que cuanto más lo leo más errores encuentro. ¿En cuántas lineas dejaríais la clase?  ¿Qué errores le veis?&lt;br /&gt;&lt;br /&gt;Por cierto, todas nuestras entradas de festival del humor son genuinas y auténticas.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8618841044787531046-5079290562359549952?l=www.nocompila.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.nocompila.com/2011/10/festival-del-humor-iv.html</link><author>noreply@blogger.com (Pedro)</author><thr:total>5</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8618841044787531046.post-3098107615270007335</guid><pubDate>Tue, 18 Oct 2011 23:47:00 +0000</pubDate><atom:updated>2011-10-20T16:44:29.684+02:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>real world java</category><category domain='http://www.blogger.com/atom/ns#'>svn</category><title>RWJ. Control de versiones: Subversion (y II)</title><description>&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;Como comentábamos en el post anterior,&amp;nbsp; cuando hacemos un &lt;i&gt;commit&lt;/i&gt; de un directorio del proyecto (el raíz tambien es un directorio)&amp;nbsp; SVN va a comprobar que, para cada fichero marcado como modificado, la versión &lt;i&gt;base&lt;/i&gt; del fichero en nuestra&amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;&lt;i&gt;working copy&lt;/i&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;&amp;nbsp; coincide con la última versión de ese fichero subido al repositorio. En caso de no coincidencia sería necesario actualizar primero los contenidos de la working copy con la última versión que hay en el repositorio.&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;Los directorios también mantienen un número de versión que cambia cuando cambia el número de versión de alguno de sus contenidos. Además es posible guardar un comentario con cada &lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;&lt;i&gt;commit&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;¿Y esto llega para todo lo que hablamos? ¿Marcar versiones entregadas del código fuente del proyecto? ¿Mantener ramas de desarrollo paralelas? ¿Sólo con esto?&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;Pues para conseguir esto hay que basarlo en convenciones. Cuando se crea un repositorio y &lt;b&gt;antes&lt;/b&gt; de empezar a subir ficheros &lt;b&gt;hay que&lt;/b&gt; crear tres directorios :&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;branches&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;tags&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;trunk&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;Una vez creados estos directorios en el repositorio ( que, por ejemplo, tendrá la url &lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;http://repo/svn/miproyecto/&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt; ) cada integrante del equipo de desarrollo tendrá que hacer un checkout sobre &lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;http://repo/svn/miproyecto/trunk &lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;. Este directorio albergará la rama principal de desarrollo y todo el equipo trabajará contra él.&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;Independientemente de que las versiones de svn se numeren secuencialmente es recomendable nombrar cualquier software con un formato&amp;nbsp;&lt;/span&gt;&lt;i&gt; &lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;x.y.z&lt;/span&gt;&lt;/i&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;&amp;nbsp;&amp;nbsp; . Cambios pequeños en el software - por ejemplo, corrección de bugs- deberían incrementar el número &lt;/span&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;z&lt;/span&gt;&lt;/i&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt; . Cambios funcionales notorios deberían incrementar el número &lt;/span&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;y&lt;/span&gt;&lt;/i&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;, mientras que el valor de &lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&lt;i&gt;x&lt;/i&gt; &lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;aumentaría sólo con cambios profundos en el producto.&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;Cuando el código de &lt;i&gt;trunk &lt;/i&gt;cumple con los objetivos que el equipo de desarrollo ha marcado para liberar una versión del programa se lanza sobre el repositorio un &lt;i&gt;copy to&lt;/i&gt;&amp;nbsp;de la rama &lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;/trunk&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt; en un directorio con la versión de software, por ejemplo,&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt; /tags/1.0.0&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt; . En las observaciones de esta operación es recomendable indicar el changelog del software.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;De esta manera, el directorio &lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;/tags/1.0.0&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt; pasaría a contener la versión 1.0.0 del software , mientras que el equipo de desarrollo seguiría desarrollando con su working copy apuntando a &lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;/trunk &lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;. Sucesivas versiones del software se marcarían de esta misma forma.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;En proyectos más complejos en los que es necesario dar soporte a diferentes versiones del producto puede surgir la necesidad de abrir una rama de desarrollo paralela al trunk &amp;nbsp;- cuya última versión liberada fue la 3.5.1 - &amp;nbsp;por ejemplo, para corregir bugs sobre una versión 2.2.0 . En este caso el procedimiento a seguir sería hacer un &lt;i&gt;copy to &lt;/i&gt;de&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt; /tags/2.2.0&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt; a &lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;/branches/2.2.x&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt; &amp;nbsp;, comentando la apertura de una rama paralela de desarrollo. El equipo responsable de la rama debería hacer un nuevo checkout del proyecto sobre la URL &lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;http://repo/svn/miproyecto/branches/2.2.x&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt; . Nuevas versiones del programa desarrollado sobre el trunk se seguirán etiquetando como hasta ahora mientras que las nuevas releases del branch se etiquetarán manteniendo las versiones de la rama. En nuestro caso el número de la siguiente versión sería 2.2.1&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;Por último, puede que modificaciones de algunos ficheros en la rama deban pasar al trunk - es el sentido habitual de incorporación-. En estas circunstancias es cuando procede hacer un &lt;i&gt;merge &lt;/i&gt;de ambas ramas. Esta parte es un poco más compleja y la maestría haciendo merges sólo se consigue haciendo muchos.&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,sans-serif;"&gt;Si no estáis usando un sistema de control de versiones, ¿a qué esperáis?&amp;nbsp;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8618841044787531046-3098107615270007335?l=www.nocompila.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.nocompila.com/2011/10/rwj-control-de-versiones-subversion-y.html</link><author>noreply@blogger.com (Pedro)</author><thr:total>0</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8618841044787531046.post-4384907750726610278</guid><pubDate>Tue, 18 Oct 2011 05:30:00 +0000</pubDate><atom:updated>2011-10-18T09:19:37.933+02:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>real world java</category><category domain='http://www.blogger.com/atom/ns#'>svn</category><title>RWJ. Control de versiones: Subversion (I)</title><description>&lt;span style="font-family: verdana;"&gt;Uno de los primeros conceptos que solemos abordar cuando incorporamos un programador sin experiencia a nuestro equipo de trabajo es el de &lt;/span&gt;&lt;span style="font-family: verdana; font-style: italic;"&gt;sistema de control de versiones&lt;/span&gt;&lt;span style="font-family: verdana;"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;div style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;span style="font-size: small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;i&gt;&lt;span style="font-family: Verdana,sans-serif; font-size: small;"&gt;- ¿Alguna vez has hecho una práctica en equipo, cada uno programando un módulo?&lt;br /&gt;- Si, una vez hicimos una aplicación web y mientras mi compañero escribía las páginas yo programaba el acceso a los datos.&lt;br /&gt;- ¿Cómo compartíais los ficheros?&lt;br /&gt;- Con una carpeta compartida de Windows.&lt;br /&gt;- ¿Y podíais seguir trabajando cada uno en vuestra casa y al día siguiente juntar los cambios?&lt;br /&gt;- No, teníamos que estar trabajando juntos con acceso a la red de Windows.&lt;br /&gt;- ¿Guardábais versiones del código que generábais? &lt;/span&gt;&lt;span style="font-family: Verdana,sans-serif; font-size: small;"&gt;&lt;br /&gt;- Si, a última hora sacábamos un .zip con la fecha y la hora en el nombre del fichero.&lt;br /&gt;- ¿No era un poco coñazo que si uno tocaba un fichero, al otro le dejase de compilar el proyecto? ¿Podías modificar los dos el fichero a la vez?&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;&lt;div style="font-family: Verdana,sans-serif;"&gt;&lt;i&gt;&lt;span style="font-size: small;"&gt;- &lt;/span&gt;&lt;span style="font-size: small;"&gt;No...&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-family: verdana;"&gt;Los &lt;/span&gt;&lt;span style="font-family: verdana; font-style: italic;"&gt;sistemas de control de versiones&lt;/span&gt;&lt;span style="font-family: verdana;"&gt;, a veces llamados también repositorios de código fuente - aunque un repositorio de código fuente no tiene por qué gestionar versiones- son herramientas diseñadas para evitar estos problemas (y algunos otros) de forma que facilitan:&lt;/span&gt;&lt;br /&gt;&lt;ul style="font-family: verdana;"&gt;&lt;li&gt;Trabajar simultáneamente sobre un mismo proyecto a más de una persona.&lt;/li&gt;&lt;li&gt;Registrar qué cambios se han hecho en cada momento en el proyecto, quién los ha hecho o recuperar una versión antigua&lt;/li&gt;&lt;li&gt;Publicar los cambios que un integrante del equipo de proyecto ha hecho una vez están terminados, y no antes ( cuando puede que ni siquiera compile el proyecto). &lt;/li&gt;&lt;li&gt;Trabajar de manera &lt;span style="font-style: italic;"&gt;offline&lt;/span&gt; , de manera que los cambios se pueden hacer fuera de la red y publicarlos después de un tiempo.&lt;/li&gt;&lt;li&gt;Etiquetar los diferentes entregables elaborados durante la duración del proyecto.&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-family: verdana;"&gt;Los sistemas de control de versiones se clasifican en &lt;/span&gt;&lt;span style="font-family: verdana; font-style: italic;"&gt;conectados &lt;/span&gt;&lt;span style="font-family: verdana;"&gt;y &lt;/span&gt;&lt;span style="font-family: verdana; font-style: italic;"&gt;desconectados&lt;/span&gt;&lt;span style="font-family: verdana;"&gt;. Ejemplos de los primeros son CVS o SourceSafe. De los segundos: SVN, Git, Mercurial . La diferencia radica en que los entornos conectados requieren de una conexión continua al repositorio y éste controla, en cada momento, qué usuario está tocando qué ficheros; mientras que los entornos desconectados no requieren de conexión contínua. El principal inconveniente de estos últimos es que, como cada programador no tiene por qué saber si alguien más está editando los mismos ficheros, pueden aparecer modificaciones simultáneas de un mismo fichero de manera más habitual.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: verdana;"&gt;Los sistemas &lt;/span&gt;&lt;span style="font-family: verdana; font-style: italic;"&gt;&lt;span style="font-style: italic;"&gt;conectados&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family: verdana;"&gt; han caído en desuso por su menor flexibilidad, y de los desconectados, el sistema con creces más usado es Subversion - SVN - .&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Subversion&lt;/span&gt; se basa en la existencia de un repositorio centralizado de código en un servidor único, contra el que los diferentes desarrolladores interactúan mediante programas cliente como TortoiseSVN. La comunicación entre los clientes y el servidor se puede realizar mediante diferentes protocolos, siendo el más común http.&lt;br /&gt;&lt;br /&gt;El repositorio SVN es un directorio en el servidor en el que se pueden subir ficheros y crear estructuras de directorios. Cada vez que se hace una subida o modificacion en el repositorio se aumenta el número de versión de los ficheros modificados y se almacena el login del usuario que realizó el cambio. Adicionalmente, se guarda un histórico de todas las versiones anteriores por las que ha pasado cada fichero.&lt;br /&gt;&lt;br /&gt;Para recuperar una cierta versión del código el servidor busca las versiones de cada fichero con el mismo número de versión o con el mayor número posible por debajo. La última versión es la HEAD.&lt;br /&gt;&lt;br /&gt;La dinámica de trabajo con SVN es simple. El programador hace un &lt;span style="font-style: italic;"&gt;checkout &lt;/span&gt;de la versión HEAD del repositorio, cuyo resultado es la obtención de una &lt;span style="font-style: italic;"&gt;working copy &lt;/span&gt;en su sistema de ficheros local. Este código puede ser modificado por el programador. Cuando el programador finaliza su trabajo hace un &lt;span style="font-style: italic;"&gt;commit &lt;/span&gt;de sus ficheros de manera que sus modificaciones pasan a formar parte del repositorio, incrementando en una unidad la versión del código fuente.&lt;br /&gt;&lt;br /&gt;Dado que el programador no tiene por qué estar trabajando solo, en cualquier momento puede hacer un &lt;span style="font-style: italic;"&gt;update&lt;/span&gt; del código de manera que se actualiza su &lt;span style="font-style: italic;"&gt;working copy&lt;/span&gt; con los nuevos cambios que otros programadores puedan haber realizado.&lt;br /&gt;&lt;br /&gt;Si durante este tiempo otro programador ha modificado uno de nuestros ficheros, en el proceso de &lt;span style="font-style: italic;"&gt;update&lt;/span&gt; aparecerá un &lt;span style="font-style: italic;"&gt;conflict&lt;/span&gt; que habrá que resolver, unificando las modificaciones realizadas por nosotros mismos con las del otro programador. Si las modificaciones afectan a partes diferentes del fichero se suelen resolver de manera automática, pero en muchas ocasiones surge la necesidad de &lt;span style="font-style: italic;"&gt;resolver &lt;/span&gt;los conflictor haciendo un &lt;span style="font-style: italic;"&gt;merge&lt;/span&gt; de ambas versiones de los ficheros.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: verdana; font-size: small;"&gt;&lt;span style="font-style: italic;"&gt;- Si, vale, muy bien, todo esto ya me lo sé que lo leí el otro día en un blog&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: verdana; font-size: small;"&gt;&lt;span style="font-style: italic;"&gt;- Pues enseguida te cuento cómo trabajar con esto, que es lo que no cuentan en todos los blogs. &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: verdana;"&gt;&lt;span style="font-style: italic;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: verdana;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: verdana;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8618841044787531046-4384907750726610278?l=www.nocompila.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.nocompila.com/2011/10/rwj-control-de-versiones-subversion.html</link><author>noreply@blogger.com (Pedro)</author><thr:total>2</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8618841044787531046.post-6453707881872779435</guid><pubDate>Mon, 17 Oct 2011 18:11:00 +0000</pubDate><atom:updated>2011-10-18T08:55:14.588+02:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>real world java</category><title>Real World Java  - RWJ -</title><description>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/-lAFLKET3arA/TpyZZN0kyJI/AAAAAAAAABc/-FjOhTqsDiE/s1600/duke_sign.png"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 200px; height: 188px;" src="http://3.bp.blogspot.com/-lAFLKET3arA/TpyZZN0kyJI/AAAAAAAAABc/-FjOhTqsDiE/s200/duke_sign.png" alt="" id="BLOGGER_PHOTO_ID_5664571089811196050" border="0" /&gt;&lt;/a&gt;&lt;span style="font-family:verdana;"&gt;Cada vez que un estudiante de informática sale del entorno académico para incorporarse al mundo laboral como programador se enfrenta a un sinfín de novedades, no sólo tecnológicas, si no sobre todo organizativas. Se dejan a un lado las prácticas, que muchas veces parecían enormes, para formar parte de proyectos realizados por equipos de varias personas, cientos (o miles) de horas, problemas de gestión de configuración, múltiples entornos,...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;En nuestro entorno profesional tenemos bastante suerte y los chicos que se incorporan a la empresa suelen ser titulados universitarios (o casi) en informática, algunos de ellos con las cosas bastante claras. Sin embargo, siempre acabamos teniendo que contar lo mismo: herramientas de control de versiones, compilación, estilos de programación, arquitectura, diseño, etc. En varias ocasiones hemos pensado en escribir sobre ello: hacer una especie de manual de formación para novatos. Pero los blogs son más divertidos.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;La idea es ir escribiendo una serie de entradas sobre algunos de estos temas: herramientas, entornos ... y sobre todo, estilos de programación.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Muchas veces la gente que comienza en este mundo olvida que el fin de todo esto es hacer negocio. Y las diferentes empresas siguen diferentes políticas a la hora de hacer este negocio. Nosotros creemos que la calidad del producto sí es importante. Y empieza por hacer que nuestro trabajo se haga siempre igual, pero mejorando cada vez un poco más.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8618841044787531046-6453707881872779435?l=www.nocompila.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.nocompila.com/2011/10/real-world-java-rwj.html</link><author>noreply@blogger.com (Pedro)</author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-lAFLKET3arA/TpyZZN0kyJI/AAAAAAAAABc/-FjOhTqsDiE/s72-c/duke_sign.png' height='72' width='72'/><thr:total>2</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8618841044787531046.post-2108126571524821781</guid><pubDate>Thu, 01 Sep 2011 17:01:00 +0000</pubDate><atom:updated>2011-09-01T19:12:21.670+02:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>mac</category><title>Mac OS X Lion ¿Poca duración de batería?</title><description>Buenas. Ya sé que no va de programación, pero bueno, tampoco es nada fácil dar con esto. &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Pues resulta que hace no mucho tiempo empecé a notar un bajón notable en la autonomía de mi macbook pro, del orden de 4h30 a 3h de batería. Se me juntó eso con la actualización a Lion y empecé a echarle la culpa a esto. Pero seguía rechinándome. &lt;i&gt;No puede ser. &lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;Total, que hablando con un amigo se me encendió la lucecita mientras le estaba contando cómo los mac pro tenían dos gráficas y cambiaban dinámicamente para ahorrar energía. ¿Sería que no pasaba a la integrada? &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Hay un programa que se llama &lt;i&gt;&lt;a href="http://codykrieger.com/gfxCardStatus"&gt;gfxCardStatus&lt;/a&gt; &lt;/i&gt;que te permite ver el estado de la gráfica del mac. Lo instalo y bingo, sólo con el navegador abierto, tarjeta dedicada activa. Además tiene un valor añadido, te dice qué módulos son los que fuerzan a estar activa a la tarjeta dedicada. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Pues resulta que Firefox (y Chrome también) hacen que la tarjeta gráfica dedicada se active - por temas de aceleración gráfica - con el consiguiente bajón de batería. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;En resumen, navegar con Firefox consume un 30% más de batería que navegar con Safari en un Macbook Pro con tarjeta gráfica dual. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8618841044787531046-2108126571524821781?l=www.nocompila.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.nocompila.com/2011/09/mac-os-x-lion-poca-duracion-de-bateria.html</link><author>noreply@blogger.com (Pedro)</author><thr:total>0</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8618841044787531046.post-2528164863614554820</guid><pubDate>Wed, 24 Aug 2011 07:05:00 +0000</pubDate><atom:updated>2011-08-24T09:07:46.875+02:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>humor</category><title>Festival del Humor (III)</title><description>Me acaba de saltar el proxy con esta url de malware&lt;br /&gt;&lt;br /&gt;&lt;img style="width: 827px; height: 579px;" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA8UAAAKjCAIAAAC7ijrIAAAgAElEQVR4nOzde3wc9X3v/7VJe0570qb99ZzD6aNtmp6eNjkp+SVp09yAJA1pm0sBJ0QJCaEpkJCEQAhEYAwYRLCh4B8mi4WxLSUhhGB8Xflug215JUXG67tkCVmyJeuylnZ129X9Zu/vj9mdncv3OzP73dXF3tfz8Xkk8mgu3/nOd2beGo0WX7hnmKIoiqIoiqIotfKFu4cpiqIoiqIoilIrX0f3EEVRFEVRFEVRauVrjw5RFEVRFEVRFKVWvjW/fI2iKIqiqEyr9FdrX9+040hN06zfy71XU1v3sVNnj9e3HDxWn2Udr285dupsU1u3bFtHappe37Sj9FdrZ/1IUVT25Xy++0bHpyiKoiiKyrSGRibOtLS/uq7sSM2ZtsjQ3K+6pvMHj57q7R8Ym5iYmJrKssYmJnr7Bw4era0/02nf1uGTTa+uKzvT0j40MjHrR4qisi/n892XyM6s7x5FURRFzWI1tbSv3bS9NTI496v8t8ci3b3jE1Nj45M5qfGJqUi0r7z6uH1bazdtb2ppn/WjQ1G5Ldn5Tp6mKIqiKPUaHB5b88u1rV2Dc7+CB0+Ojk0Mj04MjYx7r8HhMWMZvzU8OjE6NhE8eNK+rTW/XMuTaeryK9n5nm2eHhmfoiiKoqhLpTZs3LRl67bcrnPVz39zrmtwOqqhJfp2c6ShJdrY1numo+9YXcsLL6559rmfnXi7VWFtO/f+dnR80h6RtRoYGo0PjcaHRmKDo7FB7evR+NDowNBobHA0NjASGxwdGBq1ZOvR8cmde39r39aqn//G0kuTU4kjTW3v+fZr7/i3Xz218eSFxNR4vL/y05+sm+ebmD//gs93wTd/ZJ6vz+eb9UFC5WeNjk+NTVwYn0zW2MSFUdFswvM96zw9NklRFEVRl0Q1t7Rt3rx506ZNrW3hHK72pZ+/2tI5oFBv7C0/eLTOYYbj9eeOnmo+Xn/u6KmzJb989bbbblu5cmVxcfFtt932/Asrj9W1ZLS5HXurRsbGB4ZH40MjlooNDvcPDvcODPXGzTUw1Dcw1BsfWvjwI73xodjgsHGpgeHRkbHxHXur7Nt66eevGrtoajJxMZFY8ORu39f3zL/jyB/evvfM+YHExamRU3Wd7/z9Cz7fxXlXXJjnG5nn6/G949x836wPFSrfanR88lz3UGnl2dtfPnz10/tuf/lwaeXZc91Do+PWOYXnO3maoiiKypfaum378ePHjx07tn3HzhyuVi1Pb91VHovFQoePOsxTeajmzeCh5S+svP2OO1auXNnW1rZ79+79+/efOHFi+fLl3/nOd0tffq2+uct7nh4eHY8PjvYPjOjVFx/uiw/3xoa7Y0PBqkPX3/j1v3j/P/ze//qr937k2q989Rt7D1R2x4YWLnrc99/+e3dsqCc2bFw2Pjg6POopTycSicnJyf9z907fHW/57jzu+0bwyUBN4mLi4lTi3L/8y7hv3tQVvvF582K+K7rn+Vp85GlqRmt0bPJc99Ajm2o++uQbxnpkU8257qFR88zkaYqiKCp/q7mlbffu3S0tLS0tLbt27crhI+qXSl9tPj+QUTW29b740kuJRKKvr6+pvU8228o1L992+x0rV648c+bM0aNHA4HA0NDQ+Pj4zp079+3bV1lZ+fTTT3/72/+x5heeGrD9zaqhkfH+gZHe2LBePf1D0f6hjq7eRY8svvJvPvj+T/7zRz57/Ueuu/5Dn/6393/8c1f+zYc+t+Abf/vRf/rLqz4a7Rvs7hsyLts/MDI0Mr79zSr7tl4qNeXpixcSianE1Y/un39r9fw735r/zaqvLz+WSEwmEomzNy0Y8r0jMc93wXfF4Dxf2OdrnH/FrI8WKq9qbHyq9EDjPxbterKs5lx0cHxi6lx08Mmymn8s2lV6oHFsfMo4s/B8z1Gert9SVNaQSdMbAkWllZ2SiZ3VJYLvmivjLc52TUuDhd04A9UQKNJsqUtPjFaWJKcWlVSHDfPXlRUZ972urMiipCrqsLlwVak2W6A+vYbk153VJUWWjeptMy0yJ/vWZRPZ7LilS/VV2QahsLssDdP/aW9wBr2di+PotI/Wqt9iH4qZHw4v/aOy5pk/uPbu8nZiWntANFtD8twvqQ5r89uudeGq0qL0KJrGMSNb1dDIeMu59j173qipqTl//nxnZ2dNTc2eN95sOdc+NDLu+VBKa2Xpq2fPD3ivyh2/emXhNb984JrejtOJROK3R07J5rznnntCodCxY8e2bdu2devWPXv2JBKJqamp11577Re/+MVLL720fv363bt333TTTV62u+3NqoHhsd74cHf/kFbRvsFI32BX78Dt3/nBez74iY/9842f+uJXflj4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" alt="" /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8618841044787531046-2528164863614554820?l=www.nocompila.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.nocompila.com/2011/08/festival-del-humor-iii.html</link><author>noreply@blogger.com (Pedro)</author><thr:total>1</thr:total></item></channel></rss>
