select
DropStmt = 'ALTER TABLE [' + ForeignKeys.ForeignTableSchema +
'].[' + ForeignKeys.ForeignTableName +
'] DROP CONSTRAINT [' + ForeignKeys.ForeignKeyName + ']; ',
CreateStmt = 'ALTER TABLE [' + ForeignKeys.ForeignTableSchema +
'].[' + ForeignKeys.ForeignTableName +
'] WITH CHECK ADD CONSTRAINT [' + ForeignKeys.ForeignKeyName +
'] FOREIGN KEY([' + ForeignKeys.ForeignTableColumn +
']) REFERENCES [' + schema_name(sys.objects.schema_id) + '].[' +
sys.objects.[name] + ']([' +
sys.columns.[name] + ']) ON DELETE CASCADE; '
from sys.objects
inner join sys.columns
on (sys.columns.[object_id] = sys.objects.[object_id])
inner join (
select sys.foreign_keys.[name] as ForeignKeyName
,schema_name(sys.objects.schema_id) as ForeignTableSchema
,sys.objects.[name] as ForeignTableName
,sys.columns.[name] as ForeignTableColumn
,sys.foreign_keys.referenced_object_id as referenced_object_id
,sys.foreign_key_columns.referenced_column_id as referenced_column_id
from sys.foreign_keys
inner join sys.foreign_key_columns
on (sys.foreign_key_columns.constraint_object_id
= sys.foreign_keys.[object_id])
inner join sys.objects
on (sys.objects.[object_id]
= sys.foreign_keys.parent_object_id)
inner join sys.columns
on (sys.columns.[object_id]
= sys.objects.[object_id])
and (sys.columns.column_id
= sys.foreign_key_columns.parent_column_id)
) ForeignKeys
on (ForeignKeys.referenced_object_id = sys.objects.[object_id])
and (ForeignKeys.referenced_column_id = sys.columns.column_id)
where (sys.objects.[type] = 'U')
and (sys.objects.[name] not in ('sysdiagrams'))
Borrar todos los datos en todas las tablas de una db en SQL Server
EXEC sp_MSForEachTable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL' GO
EXEC sp_MSForEachTable 'DELETE FROM ?' GO
EXEC sp_MSForEachTable 'ALTER TABLE ? CHECK CONSTRAINT ALL' GO
Como buscar las dependencias de FK en SQL Server
SELECT
K_Table = FK.TABLE_NAME,
FK_Column = CU.COLUMN_NAME,
PK_Table = PK.TABLE_NAME,
PK_Column = PT.COLUMN_NAME,
Constraint_Name = C.CONSTRAINT_NAME
FROM
INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS C
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS FK
ON C.CONSTRAINT_NAME = FK.CONSTRAINT_NAME
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS PK
ON C.UNIQUE_CONSTRAINT_NAME = PK.CONSTRAINT_NAME
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE CU
ON C.CONSTRAINT_NAME = CU.CONSTRAINT_NAME
INNER JOIN (
SELECT
i1.TABLE_NAME,
i2.COLUMN_NAME
FROM
INFORMATION_SCHEMA.TABLE_CONSTRAINTS i1
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE i2
ON i1.CONSTRAINT_NAME = i2.CONSTRAINT_NAME
WHERE
i1.CONSTRAINT_TYPE = 'PRIMARY KEY'
) PT
ON PT.TABLE_NAME = PK.TABLE_NAME
ORDER BY PK_Table
Fuente: Stackoverflow
CRUD en servicios API REST
Me encuentro trabajando en un pequeño proyecto donde estoy creando un pequeño servicio REST en nodejs . La idea de este post es resumir un poco los usos que podemos hacer de los verbos HTTP y explicar las interacciones y los procesos que intervienen en la mayoría de los servicios REST.
Contrato del servicio REST
| POST | /pedido | Crea un nuevo pedido en el sistema. |
| GET | /pedido:id | Solicitación de un determinado pedido por id. |
| PUT | /pedido:id | Modificación de un determinado pedido por id. |
| DELETE | /pedido:id | Borra un determinado pedido por id. |
A continuación vamos a ver las interacciones y procesos que realiza cada uno de los métodos en nuestro servicio REST.
POST: /pedido – Creación de un pedido
Verbo HTML:
POST
Posibles respuestas:
- 201 Created – Y también se envía el encabezado “Location” con la url del recurso completo.
- 400 Bad Request – Cuando el cliente envía una url incorrecta.
- 500 Internal Server Error – Cuando un error ocurre en el proceso realizado en el server.
POST /pedido HTTP/1.1
Host: api.pedidos.com
Content-Type: application/json
{
"codigo":"1",
"titulo":"Pedido prueba",
"fecha":"11/11/2012",
"servicio":"Cambio de disco duro",
"tecnico":"juan perez"
}
/*respuesta*/
HTTP/1.1 201
Created Content-Type:
application/json
Location: http://api.pedidos.com/pedido/1
GET: /pedido/:id Solicitud de un determinado pedido
Verbo HTML:
GET
Posibles respuestas:
- 200 OK – Y también se representa el pedido completo.
- 404 Not Found – No se encontró el pedido en el servidor.
- 500 Internal Server Error – Cuando un error ocurre en el proceso realizado en el server.
GET /pedido/1 HTTP/1.1
Host: api.pedidos.com
//respuesta
HTTP/1.1 200 OK
Content-Type: application/json
{
"codigo":"1",
"titulo":"Pedido prueba",
"fecha":"11/11/2012",
"servicio":"Cambio de disco duro",
"tecnico":"juan perez"
}
PUT: /pedido/:id Modificación de un determinado pedido
Verbo HTML:
Usamos PUI aunque no haya una convención directa.
Sugerencias:
Use POST para crear un recurso identificado una URI de servicio.
Use POST para añadir un recurso a una colección identificado por un servicio generado.
Use PUT para crear o sobrescribir un recurso identificado por un URI calculado por el cliente
Posibles respuestas:
- 200 OK o 204 No Content.
- 404 Not Found – No se encontró el pedido en el servidor.
- 409 Conflict – La solicitud no se pudo completar debido a un conflicto con el estado actual del pedido.
- 500 Internal Server Error – Cuando un error ocurre en el proceso realizado en el server.
PUT /pedido/1 HTTP/1.1
Host: api.pedidos.com
Content-Type: application/json
{
"codigo":"1",
"titulo":"Pedido nueva prueba",
"fecha":"11/11/2012",
"servicio":"Cambio de disco duro",
"tecnico":"juan perez"
}
//respuesta
HTTP/1.1 200 OK
Content-Type: application/json
{
"codigo":"1",
"titulo":"Pedido nueva prueba",
"fecha":"11/11/2012",
"servicio":"Cambio de disco duro",
"tecnico":"juan perez"
}
DELETE /pedido/:id Borrar un determinado pedido.
Verbo HTML:
DELETE
Posibles respuestas:
- 204 No Content.
- 404 Not Found – No se encontró el pedido en el servidor.
- 405 Method not allowed – Si el pedido ya esta concretado el recurso no se podrá eliminar.
- 503 Service Unavailable – El servicio no tiene una implementación para eliminación del pedido.
DELETE /pedido/1 HTTP/1.1
Host: api.pedidos.com
//respuesta
HTTP/1.1 204 No Content
Node.js – Modulos y require.cache
Si estas comenzando con Node.js quizás hayas notado un comportamiento extraño en instancias de un mismo modulo.
Veamos los siguientes tests..
var i = require('./a.js');
var o = require('./a.js');
var assert = require('assert');
describe('test1', function(){
it('tt', function(){
assert.equal(i.text(), 'texto desde el modulo');
});
it('tt1', function(){
i.text = function () { return 'el texto cambio' };
assert.equal(i.text(), 'el texto cambio');
});
it('tt2', function(){
assert.equal(o.text(), 'texto desde el modulo');
});
});
Algunas personas quizás piensen que los tres tests se completan con éxito, pero en realidad el tercero falla. Esto pasa porque node.js cachea todas las llamadas require, el código del modulo es solo ejecutado una vez en toda la aplicación.
Si por alguna razón necesitas borrar algún modulo del require.cache lo podes hacer de la siguiente manera.
delete require.cache[require.resolve('./a.js')]
Finalmente quiero dar las gracias a @jfroma que me explicó esto.
MS Access a SQL Server: Problemas con booleanos post conversión
MS Access y SQL Server tratan de diferente manera a los booleanos, en MS Access -1 es True y 0 es False. En cambio en la base de datos SQL Server se usa el tipo BIT (1 para True y 0 para False).
Luego de realizar la exportación de tablas MS Access a SQL Server es probable que si quieras seguir trabajando con Access como Front tengas muchos problemas con los booleanos.
Una solución es cambiar todos los tipos BIT a Smallint, para así pasar los valores 1 a -1. También hay que realizar los cambios en los valores por default.
A continuación les muestro el Stored Procedure que hice para cambiar todos los tipos BIT a Smallint de todas las tablas.
USE [BaseDeDatosSQL]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[MAIN_CONVERTIR_BOOLEAN_A_SMALLINT]
AS
BEGIN
SET NOCOUNT ON;
DECLARE @nombre_constraint AS NVARCHAR(4000)
DECLARE @SQL AS NVARCHAR(4000)
DECLARE @nombre_tabla AS NVARCHAR(255)
DECLARE @nombre_columna AS NVARCHAR(255)
DECLARE @nuevo_valor_default AS INTEGER
DECLARE CUR CURSOR FAST_FORWARD FOR
SELECT c.table_name,
c.column_name,
CASE
WHEN c.column_default = '((1))' THEN -1 ELSE 0
END AS nuevo_valor_default
FROM INFORMATION_SCHEMA.COLUMNS c
WHERE c.data_type = 'bit'
AND c.table_catalog = 'BaseDeDatosSQL'
AND c.table_schema = 'dbo'
-- AND c.table_name = 'nombre_tabla'
OPEN CUR
FETCH NEXT FROM CUR INTO @nombre_tabla,
@nombre_columna, @nuevo_valor_default
WHILE @@FETCH_STATUS = 0
BEGIN
SET @nombre_constraint =
(
SELECT name
FROM sysobjects so JOIN sysconstraints sc
ON so.id = sc.constid
WHERE object_name(so.parent_obj)
= @nombre_tabla
AND so.xtype = 'D'
AND sc.colid =
(SELECT colid FROM syscolumns
WHERE id =
object_id(@nombre_tabla)
AND name = @nombre_columna)
)
PRINT '--- TABLA: ' + @nombre_tabla + ' COLUMNA: '
+ @nombre_columna + ' DEFAULT: '
+ RTRIM(CONVERT(CHAR, @nuevo_valor_default))
+ ' ----'
SELECT @SQL = 'ALTER TABLE [' + @nombre_tabla
+ '] ADD [Campo Temporal] SMALLINT;'
EXEC sp_executesql @SQL
SELECT @SQL = 'UPDATE ['
+ @nombre_tabla + '] SET [Campo Temporal] = ['
+ @nombre_columna + '];'
EXEC sp_executesql @SQL
SELECT @SQL = 'ALTER TABLE ['
+ @nombre_tabla + '] DROP CONSTRAINT ['
+ @nombre_constraint + ']'
EXEC sp_executesql @SQL
SELECT @SQL = 'ALTER TABLE ['
+ @nombre_tabla + '] DROP COLUMN ['
+ @nombre_columna + '];'
EXEC sp_executesql @SQL
SELECT @SQL = 'ALTER TABLE ['
+ @nombre_tabla + '] ADD ['
+ @nombre_columna + '] SMALLINT DEFAULT ('
+ RTRIM(CONVERT(CHAR, @nuevo_valor_default)) + ');'
EXEC sp_executesql @SQL
SELECT @SQL = 'UPDATE ['
+ @nombre_tabla + '] SET ['
+ @nombre_columna + '] = [Campo Temporal];'
EXEC sp_executesql @SQL
SELECT @SQL = 'ALTER TABLE ['
+ @nombre_tabla + '] DROP COLUMN [Campo Temporal];'
EXEC sp_executesql @SQL
SELECT @SQL = 'UPDATE ['
+ @nombre_tabla + '] SET ['
+ @nombre_columna + '] = ['
+ @nombre_columna + '] * -1;'
EXEC sp_executesql @SQL
PRINT '------------ Los cambios se realizaron con éxito --------------'
FETCH NEXT FROM CUR INTO @nombre_tabla, @nombre_columna,
@nuevo_valor_default
END
CLOSE CUR;
DEALLOCATE CUR;
END
Exportación de tablas de MS Access a SQL Server
- Abrir la base de datos MS Access
- Luego ir a la sección Herramientas de Bases de Datos y hacer click en SQL Server

- Luego seleccionar “Crear nueva Base de Datos”
- Especificar el servidor, en este caso es .\SQLEXPRESS (Si usas EXPRESS no aparecerá el server en la lista, tenes que ponerlo a mano).
- Seleccionar “Usar Conexión de Confianza” y mas abajo especifica el nombre de la base de datos que se creara en SQL Server y presionar el botón Siguiente.
- En este punto seleccionamos las tablas que queremos exportar y presionar botón Siguiente.
- Ahora seleccionamos los atributos de las tablas que deseamos exportar y presionamos Sigueinte.

- El último paso nos consulta sobre que cambios queremos realizar a la aplicación Access. En mi caso selecciono Ninguno.
- Y por ultimo presionamos “Finalizar” para dar inicio al proceso.

Probando VPS Gratis
Las VPS están en auge actualmente, en todo el mundo existen miles de empresas que brindan este servicio y esto generó gran competencia entre ellas. Los precios por VPS están bajando y hasta incluso algunos dan la posibilidad de tener una VPS gratis de por vida.
Son pocas las empresas que están ofreciendo VPS gratis de por vida, Host1Free es una de ellas que además de ofrecer VPS gratis también regalan hosting.
Para solicitar mi VPS rellené el formulario en la web y luego de un par de días me activaron la cuenta.
Características del Servicio:
La VPS es una maquina virtual tipo OpenVZ con 128 MB de RAM y ancho de banda ilimitado. Se administra con SolusVM y es posible reinstalar el sistema operativo, yo utilicé Centos 6 pero existen otras imágenes como Ubuntu o Centos 5 por ejemplo.
El desempeño de la conexión no es el de las mejores VPS que pude ver, la descarga de archivos raramente supera los 800K.
La RAM es muy limitada pero es posible instalar un server MySQL y NGINX funcionando aceptablemente bien.

Con respecto a la performance I/O del disco está bastante bien:
[root@xfigue ~]# dd if=/dev/zero of=test bs=64k count=16k conv=fdatasync
16384+0 records in
16384+0 records out
1073741824 bytes (1.1 GB) copied, 32.0667 seconds, 33.5 MB/s
Y el tracert..

Conclusiones:
La VPS funciona aceptablemente bien aunque tenga muy poca memoria RAM y el rendimiento del disco (I/O Test) esta bien, se podria decir que es lo normal. Recordemos que para un blog con wordpress y pocas visitas 10 MB/s (I/O) alcanza y sobra
.
El punto en contra que tiene es el ancho de banda, algo entendible porque están dando acceso a internet ilimitado, algún tipo de control de ancho de banda existirá.
La ubicación geográfica del server donde está montada la vps no es favorable para visitas de la Argentina dado que se encuentra en Alemania.
NHIbernate 3.2 – Mapeando por código
Una de las cosas que no me gustaba de NHIbernate era hacer los mappings a mano en formato XML, es tedioso y siempre lo intento evitar.
Por suerte con la versión 3.2 de NHIbernate introdujo una herramienta para mapear por código, esta herramienta al principio se llamaba ConfORM y luego los desarrolladores decidieron incluirla en el core del Framework.
Ahora les mostraré como mapear un pequeño conjunto de clases y generar el esquema de la base de datos.
Referencias:
Antes que nada necesitamos agregar un par de referencias a nuestro proyecto para trabajar con NHIbernate utilizando la herramienta NuGet.
Luego buscaremos la palabra “NHIbernate”, después presionamos “Install” en el primer ítem del resultado de la búsqueda.
Luego podremos observar que las dlls ya estan en la listas de referencias.
El modelo:
El modelo tiene 3 clases que representa a un pequeño (ultra pequeño) sistema de blog.
Entidades en C#
public class Entrada
{
public virtual int Id { get; set; }
public virtual string Titulo { get; set; }
public virtual string Cuerpo { get; set; }
public virtual Usuario Usuario { get; set; }
public virtual IList Etiquetas { get; set; }
}
public class Etiqueta
{
public virtual int Id { get; set; }
public virtual string Nombre { get; set; }
}
public class Usuario
{
public virtual int Id { get; set; }
public virtual string Nombre { get; set; }
public virtual string Password { get; set; }
public virtual IList Entradas { get; set; }
}
Configuración NHibernate:
En la clase Configuration de NHIbernate podemos especificar la conexión de la base de datos que utilizaremos, en este caso vamos a usar Sql Server.
var configuration = new Configuration();
configuration.DataBaseIntegration(db =>
{
db.ConnectionProvider<DriverConnectionProvider>();
db.Dialect<MsSql2005Dialect>();
db.Driver<SqlClientDriver>();
db.ConnectionString
= @"Server=.\SQLEXPRESS;Database=nhtest;User=sqluser;Password=sqluser;";
db.BatchSize = 30;
db.KeywordsAutoImport = Hbm2DDLKeyWords.AutoQuote;
db.Timeout = 10;
db.LogFormattedSql = true;
db.LogSqlInConsole = false;
db.HqlToSqlSubstitutions
= "true 1, false 0, yes 'Y'
, no 'N'";
});
Los mappings:
public class UserMap : ClassMapping<Usuario>
{
public UserMap()
{
Id(x => x.Id, map => map.Generator(Generators.HighLow,
gmap => gmap.Params(new { max_low = 100 })));
Property(x => x.Nombre, map => map.NotNullable(true));
Property(x => x.Password, map => map.NotNullable(true));
Bag(p => p.Entradas, map =>
{
map.Key(k => k.Column("UsuarioId"));
map.Table("UsuarioEntradas");
map.Inverse(true);
},
rel => rel.ManyToMany(x => x.Column("EntradaId")));
}
}
public class EtiquetaMap : ClassMapping<Etiqueta>
{
public EtiquetaMap()
{
Id(x => x.Id, map => map.Generator(Generators.HighLow,
gmap => gmap.Params(new { max_low = 100 })));
}
}
public class EntradaMap : ClassMapping<Entrada>
{
public EntradaMap()
{
Id(x => x.Id, map => map.Generator(Generators.HighLow,
gmap => gmap.Params(new { max_low = 100 })));
ManyToOne(p => p.Usuario, map => map.Column("UsuarioId"));
Bag(p => p.Etiquetas, map =>
{
map.Key(k => k.Column("EntradaId"));
map.Table("EntradaEtiquetas");
map.Inverse(true);
},
rel => rel.ManyToMany(x => x.Column("EtiquetaId")));
}
}
Por ultimo necesitamos agregar estos mappings a la configuración de NHIbernate y generar el esquema.
var mapper = new ConventionModelMapper();
var mappings = new[]
{
typeof(UserMap),
typeof(EtiquetaMap),
typeof(EntradaMap),
};
mapper.AddMappings(mappings);
configuration.AddMapping(mapper.CompileMappingForAllExplicitlyAddedEntities());
new SchemaExport(configuration).Execute(false, true, false);
Con todo esto, NHIbernate tiene los mappings y genero automáticamente todas las tablas necesarias en la base de datos como se puede observar en el siguiente esquema.

Si quieres ver el código fuente de este ejemplo puedes entrar a mi repositorio: https://bitbucket.org/xfigue/nhibernatetests/src
También hice un video tutorial con todos estos pasos:
Instalación de Redis en Linux Centos
Si estas intentando compilar redis en Linux Centos de 32 bits es probable que obtengas algunos errores, para solucionar esto es necesario editar el archivo src/.make-settings.
nano src/.make-settings
## Modificar la variable OPT asi.
OPT=-O2 -march=i686
Ahora descargamos el código fuente de Redis y compilamos
cd /usr/src
wget http://redis.googlecode.com/files/redis-2.6.0-rc3.tar.gz
tar -xvf redis-2.6.0-rc3.tar.gz
cd redis-2.6.0-rc3
make
make install
Creamos las carpetas necesarias para Redis y el archivo de configuración.
mkdir /etc/redis /var/lib/redis
sed -e "s/^daemonize no$/daemonize yes/"
-e &/^dir \.\//dir \/var\/lib\/redis\//"
-e &/^loglevel debug$/loglevel notice/"
-e &/^logfile stdout$/logfile \/var\/log\/redis.log/"
redis.conf > /etc/redis/redis.conf
Y por ultimo instalamos el servicio.
wget https://raw.github.com/gist/257849/9f1e627e0b7dbe68882fa2b7bdb1b2b263522004/redis-server
sed -i "s/usr\/local\/sbin\/redis/usr\/local\/bin\/redis/" redis-server
chmod u+x redis-server
mv redis-server /etc/init.d
/sbin/chkconfig --add redis-server
/sbin/chkconfig --level 345 redis-server on
/sbin/service redis-server start



