Acelerando la depuracion del Framework Compacto en VS2008

Si ya sé que todos desarrollan en WP7 y usando VS2011, pero para aquellos que tienen que hacer un proyecto en VS2008 con Compact Framework 6.5, que todavía habrá algunos, bien sea por que reinstalaron la maquina o están empezando desde cero.

La compilación de estas soluciones toma demasiado tiempo, un truco que puede hacer que todo sea más rápido cuando usted ya sabe cual dispositivo el cliente correrá la aplicación, que es como el 99% de los casos, puede simplemente deshabilitar la verificación de plataforma.

Abra el archivo %windir%Microsoft.NETFrameworkv2.0.50727Microsoft.CompactFramework.Common.Targets

Vaya a la línea que dice

Name=”PlatformVerificationTask”>

y cambiela por

Name=”PlatformVerificationTask” Condition=”‘$(SkipPlatformVerification)’ != ‘true'”>

Referencias:

http://christian-helle.blogspot.com/2009/10/improve-netcf-build-performance-in.html

http://blogs.msdn.com/b/vsdteam/archive/2006/09/15/756400.aspx

y con eso todas las horas que se ahorre compilando las puede usar para migrarse a la plataforma Windows Phone 7 o Windows 6.5 Embedded o Windows 7 Embedded dependiendo de a quien quiera ayudar o que quiera hacer. Eso si mucha suerte consiguiendo los dispositivos empresariales que corran esas plataformas.

Juan Peláez
3Metas

Todas las Ciudades del Planeta. Parte 1

Por diversas razones en varios proyectos para clientes hemos tenido que crear una lista de países, ciudades, idiomas. Ahora que estamos trabajando en the Company Tool (Una herramienta de seguimiento y control de la operación para compañías pequeñas y medianas) nos encontramos con el mismo asunto e incluso ampliado porque necesitamos la lista de todos los países y ciudades del mundo, así que decidimos revisar un poco mejor si hay algo que podíamos hacer para no repetirnos y tener este problema resulto de una mejor forma. Este artículo es el producto de esa investigación y el código que construimos.

Información de todos las Ciudades.

Lo primero era obtener la lista de todos los países y ciudades del mundo, eso tenía que existir en alguna parte así que luego de un rato en internet encontramos que podíamos copiarla a mano de Wikipedia o consumir un servicio llamado GeoNames que no solo incluye Wikipedia sino muchas más fuentes, este servicio expone unos Servicios Web (web services) con JSON o XML donde se pueden realizar una serie de consultas asociadas a cualquier ciudad o país del mundo, sin embargo tiene unos limites de uso (30.000 peticiones por día y 2.000 por hora) y no queríamos depender de un servicio externo por más que este parece bastante confiable, tomamos entonces la otra opción y descargamos la data.  Ahora bien procesar 2 GB de datos no resultó tan sencillo.

Lo segundo era cargarlos a nuestro SQL 2008 R2 para poder hacer consultas, explorar las capacidades de georeferenciación (Datos geográficos) incluidos en SQL y construir nuestro propio servicio.

Cargando la Data de GeoNames en SQL Server 2008 R2.

Antes que nada hay que transformar el archivo que venia en formato UTF8 a UTF16. Algunas recomendaciones en Internet dicen que puede importarse con el asistente de SQL y la opción de encoding del archivo, pero no funcionó aunque le dimos varias vueltas así que utilizamos esta herramienta, que convierte el archivo desde UTF8 a UTF16 y que funcionó perfectamente.

Luego construimos una tabla en la base de datos con la estructura del archivo:

--CREATE TABLE Core.GeoNames(
--geonameid int NOT NULL,
--name nvarchar(200) NULL,
--asciiname nvarchar(200) NULL,
--alternatenames nvarchar(max) NULL,
--latitude float NULL,
--longitude float NULL,
--feature_class char(2) NULL,
--feature_code nvarchar(10) NULL,
--country_code char(3) NULL,
--cc2 char(60) NULL,
--admin1_code nvarchar(20) NULL,
--admin2_code nvarchar(80) NULL,
--admin3_code nvarchar(20) NULL,
--admin4_code nvarchar(20) NULL,
--population bigint NULL,
--elevation int NULL,
--gtopo30 int NULL,
--timezone char(31) NULL,
--modification_date date NULL)

Luego insertamos la data desde el nuevo archivo convertido en UTF16 en nuestra base de datos.

--BULK INSERT Core.GeoNames
--FROM 'C:ReferenceGeoNamesutf16Allcountries.txt'
--WITH( DATAFILETYPE = 'widechar',
--      FIELDTERMINATOR = 't',
--      ROWTERMINATOR = 'n')


--Select top 1000 * from Core.GeoNames

En este punto ya tenemos la data cargada y podíamos hacer consultas sobre ella, incluso tenemos unos campos con latitud y longitud pero no estamos aprovechando el poder de los datos geográficos de SQL Server 2008 R2 (incluso en su versión Express que es gratuita). Así que modificamos la tabla de GeoNames para incluir un campo geográfico. (Los campos geográficos incluyen en su análisis la curvatura de la tierra, los campos geométricos no, así que si uno quiere analizar cosas pequeñas como una bodega, almacén, etc, usando sus coordenadas gps y georeferenciacion debe usar campos geométricos, pero ese es tema de otro post)


--ALTER TABLE Core.GeoNames
--  ADD geog GEOGRAPHY NULL
--GO

Creado el campo geográfico hay que actualizarlo con la información de cada punto, nótese aquí como se construye el campo utilizando la función POINT a la que le pasamos la longitud y latitud.  (Curiosamente si se integra luego esto con GoogleMaps ellos utilizan latitud y longitud)

 --UPDATE Core.GeoNames
--  SET geog = GEOGRAPHY::STGeomFromText
--    ('POINT(' + CAST(longitude AS CHAR(20))
--    + ' ' + CAST(latitude AS CHAR(20)) + ')',4326)

Un par de índices son buenos y necesarios para las consultas sobre 9 millones de registros tengan un rendimiento aceptable.

 --ALTER TABLE Core.GeoNames
--  ADD CONSTRAINT pk_geonames_geonameid
--  PRIMARY KEY (geonameid)
--GO


--CREATE SPATIAL INDEX geonames_mmmm16_sidx
--   ON Core.GeoNames(geog)
--   USING GEOGRAPHY_GRID
--   WITH (
--     GRIDS = (MEDIUM, MEDIUM, MEDIUM, MEDIUM),
--     CELLS_PER_OBJECT = 16,
--     PAD_INDEX = ON
--   )
--GO

La información descriptiva de los países, regiones e idiomas también esta disponible en los archivos:

countryInfo.txt, admin2Codes.txt, admin1CodesASCII.txt, iso-languagecodes.txt, timeZones.txt

Con sus correspondientes scripts:


--CREATE TABLE [Core].[TimeZones](
--    [CountryCode] [nvarchar](255) NULL,
--    [TimeZoneId] [nvarchar](255) NULL,
--    [GMT offset 1# Jan 2012] [float] NULL,
--    [DST offset 1# Jul 2012] [float] NULL,
--    [rawOffset (independant of DST)] [float] NULL
--) ON [PRIMARY]


--CREATE TABLE [Core].[Iso-LanguageCodes](
--    [ISO 639-3] [nvarchar](255) NULL,
--    [ISO 639-2] [nvarchar](255) NULL,
--    [ISO 639-1] [nvarchar](255) NULL,
--    [Language Name] [nvarchar](255) NULL
--) ON [PRIMARY]


--CREATE TABLE [Core].[countryInfo](
--    [ISO] [nvarchar](255) NULL,
--    [ISO3] [nvarchar](255) NULL,
--    [ISO-Numeric] [float] NULL,
--    [fips] [nvarchar](255) NULL,
--    [Country] [nvarchar](255) NULL,
--    [Capital] [nvarchar](255) NULL,
--    [Area] [float] NULL,
--    [Population] [float] NULL,
--    [Continent] [nvarchar](255) NULL,
--    [tld] [nvarchar](255) NULL,
--    [CurrencyCode] [nvarchar](255) NULL,
--    [CurrencyName] [nvarchar](255) NULL,
--    [Phone] [float] NULL,
--    [Postal Code Format] [nvarchar](255) NULL,
--    [Postal Code Regex] [nvarchar](255) NULL,
--    [Languages] [nvarchar](255) NULL,
--    [geonameid] [float] NULL,
--    [neighbours] [nvarchar](255) NULL,
--    [EquivalentFipsCode] [nvarchar](255) NULL
--) ON [PRIMARY]


--CREATE TABLE [Core].[AdminCodes](
--    [adminCode] [nvarchar](255) NULL,
--    [name] [nvarchar](255) NULL,
--    [fullName] [nvarchar](255) NULL,
--    [geonamesId] [float] NULL
--) ON [PRIMARY]

Esta información nos permite crear una estructura de datos desde la cual podemos consultar los estados de un país (departamentos, provincias), las ciudades que hacen parte de ese estado y muchas más consultas sobre proximidad, por ejemplo cual es la ciudad de más de 15.000 habitantes más cercana a mi punto actual.

Unas consultas rápidas para entender la estructura de datos generada:

Lista de Países: (mejor obtenerla de la tabla countryInfo):


Select  * from CoreDB.Core.GeoNames Where
Feature_code = 'PCLI'
Order by Name

Lista de Departamentos (regiones, provincias) de un país:


--deptos o primer nivel
Select top 100 * from CoreDB.Core.GeoNames Where
Country_code ='CO' and Feature_code = 'ADM1'
Order By name

Donde CO es el código del país.
Lista de las ciudades que pertenecen a un depto


--Ciudades o segundo nivel
Select  * from CoreDB.Core.GeoNames Where
Country_code ='CO' and Admin1_code = 02 and Feature_code = 'ADM2'
Order By name

Donde CO es el código del país, en este caso Colombia, y Admin1_code es el código del departamento (región, provincia) seleccionado anteriormente.

Con estos datos estamos listos para construir una capa de servicios que exponga esta información, eso lo haremos en la segunda parte.

 

Juan Peláez
Arquitecto de software
3Metas Corp.
www.juanpelaez.com

 

Referencias:

http://www.geonames.org/
http://www.geonames.org/export/codes.html
http://midnightprogrammer.net/post/Integrate-Bing-Maps-With-Geonames-Database-And-ASPNET.aspx
http://forum.geonames.org/gforum/posts/list/817.page
http://blogs.msdn.com/b/edkatibah/archive/2009/01/13/loading-geonames-data-into-sql-server-2008-yet-another-way.aspx

 

Nota: Algunas de estas operaciones de procesamiento del archivo, creación de índices, etc., toman varios minutos, más de 10, en mi maquina de escritorio que es una buena maquina.

Continent codes :
AF : Africa                    geonameId=6255146
AS : Asia                      geonameId=6255147
EU : Europe                    geonameId=6255148
NA : North America             geonameId=6255149
OC : Oceania                   geonameId=6255151
SA : South America             geonameId=6255150
AN : Antarctica                geonameId=6255152

Seguridad en Internet y Planeación de Infraestructura

El pasado 8 de mayo fui invitado por el  equipo de desarrollo de soluciones y gestión de proyectos de El Nucleo Digital (la compañía creada por SanchoDDBB para la construcción y gestión de sus soluciones en internet, mobile y nuevos medios) a realizar un taller de planeación de infraestructura y seguridad en Internet, fue una muy buena experiencia y una tarde muy divertida en la que a cada participante le dimos un rol de infraestructura y logramos hacer que la operación de internet y sus diferentes elementos se convirtiera en algo tangible. Espero que ellos se hayan divertido tanto como yo.

Gracias por Invitarme.

Consumiendo Servicios REST desde iOS 5. Parte 1. Preparando el proyecto.

Últimamente he colaborado en el  desarrollo de varias aplicaciones para iOS (versiones 4 y 5), estas aplicaciones consumen servicios REST que retornan JSON o XML lo que aunque es una tarea más o menos trivial requiere algo de investigación para hacerla bien por que hay muchos frameworks, formatos y plataformas que se pueden involucrar.

Después de investigar un rato, ver algunos ejemplos y leer bastante código termine seleccionando la librería ASIHTTPRequest, esta librería es robusta y me permite hacer cosas como invocar los servicios de forma asíncrona (lo que debe ser obligatorio en aplicaciones con interfaz de usuario móvil o de escritorio) o consumir servicios que requieren autenticación por medio de headers.

Descargue las clases, agréguelas a su proyecto, no olvide incluir la clase reachability que esta en la carpeta Externals de ASIHTTPRequest  y estará listo para consumir servicios Rest desde iOS, o casi listo…

Ahora bien, hace casi un año se lanzo la versión 5 del sistema operativo iOS y eso le generará algunos problemas ya que una de sus grandes novedades fue la recolección automática de objetos (ARC), es decir que ya no había que destruir manualmente las referencias a los objetos que no se usan, algo que antes hacíamos escribiendo instrucciones como:

[shareDialog release]

Otras instrucciones como retain, dealloc tampoco son necesarias si se esta trabajando en el modo ARC (Automatic Reference Counting)

Ahora bien, estos cambios que se introducen en el compilador hacen que librerías como la que venia usando para consumir los servicios queden inservibles.  Sin embargo el compilador tiene una opción (flag) que se puede aplicar por cada archivo de clase de forma que ignore la característica de ARC para ese archivo al momento de compilar.  Instrucciones (en ingles) y unas buenas fotos de como hacerlo aquí

En este punto su solución debe compilar y ya tiene todo lo necesario para empezar a consumir servicios REST desde su aplicación iOS 4 o 5.

PD: Sobre ARC, Es importante aclara que esto es una nueva característica del compilador y no del encargado de la ejecución, así que no es ni parecido al Garbage Collector de .Net aunque podría confundirse, básicamente lo que esta pasando es que el compilador agrega las instrucciones a nuestro programa cuando lo compila

 

Juan Peláez
Arquitecto de Software

Desde hace más de un año en 3Metas, con  nuestro equipo de desarrolladores en Colombia, Bucaramanga, Manizales, Popayan, Medellin, Fort Lauderdale, Miami, Atlanta, Los Angeles, Shangai, Hawai y Australia hemos venido desarrollando aplicaciones para iOS tanto para iPad como para iPhone para clientes alrededor del  mundo.

Donde esta la salida?

En los últimos años, tampoco muchos máximo 2, se ha generado un interés en redes sociales, eventos, reportes y todo el ruido mediático del mundo en el tema de emprendimiento de base tecnológica en Colombia, si bien esto no es nuevo por que muchos programas de Proexport, el ministerio de comunicaciones y organizaciones como Endevor ya venia trabajando en el apoyo a los emprendedores si hay que destacar el renovado interés y sobre todo el nuevo enfoque de promoción del emprendimiento hacia un modelo más del tipo de Silicon Valley.

Sin embargo creo que en un periodo de no menos de 6-10 años ese modelo no será exitoso en Colombia y la razón es muy simple: en Colombia no existen mecanismos de salida que son los que garantizan la existencia de los modelos de emprendimiento en Estados Unidos.

Qué es un mecanismo de salida? Fácil, es la forma como el inversionista va a recuperar su inversión más las ganancias en algún momento, ojala próximo en el corto plazo, del tiempo.

Entonces, supongamos que usted en USA un ángel inversionista le da 50.000 dólares, ese querido amigo espera que usted venda en la ronda A a un fondo de inversión la empresa en 1 millón de dólares y que el convierta sus 50.000 en 300.000 ojala en un año. Ahora bien, y en esto también somos diferentes, y muy diferentes, si en USA la empresa se quiebra y usted nunca tiene un producto o no vende la empresa en los 300.000 en cierta medida el inversionista entiende el riesgo y en general digamos que no pasa nada. (Para cubrirse el inversionista puso 50.000 en cuatro empresas, 3 de las cuales quebraron y una se venido en 300.000 así que aun perdiendo 150.000 en las 3 empresas quebradas, recupero el 100% de la inversión y gano 100.000 más).

Qué hace el fondo que compró en la ronda A con su inversión, espera que pase una de dos: a) que haya una ronda B y vender su participación de 1 millón en 50 millones, o que la compañía se haga publica (IPO) en la bolsa de valores y su participación de 1 millón ahora valga 300 millones.

Ahora fijémonos que pasa en Colombia: Usted crea su empresa y no hay Ángeles Inversionistas (punto). Si usted consigue un inversionista de los mismos 50.000 dólares eso es un préstamo, si su empresa fracasa, el inversionista espera su retorno de los 50.000. Ok no seamos tan negativos, digamos que su empresa no fracasa, entonces que alternativas hay: a) un fondo de inversión para la ronda A, no, eso no existe en Colombia, los fondos de inversión solo invierten en ciertos sectores y el software, internet, etc, no están entre ellos. (He hablado con varios fondos así que en este punto puede creerme), le queda la alternativa b) usted mismo de las utilidades o de la operación le compra a su inversionista su parte, es decir le paga el préstamo, solo que aclaremos que como no le cobro intereses y usted en teoría le dio una participación de la compañía le esta comprando su parte. Ahora bien supongamos que no soy tan negativo y usted tiene un familiar o mejor amigo del colegio que es socio de un fondo de inversión, entonces logra una ronda A y hace historia, primero lo felicito y segundo vamos a preocuparnos por como ese fondo va a recuperar su inversión? lo que nos deja en las siguientes alternativas: a) ir a bolsa, que aunque es posible en Colombia desde hace un par de años en teoría, en la practica es casi imposible por las restricciones legales y de protección que buscan evitar que los inversionistas se arruinen. Así que muy, pero muy pocas empresas han logrado salir a bolsa. Le queda la opción b) que es comprarle usted al fondo de inversión su parte de la compañía.
En este punto esperemos que el fondo de inversión haga su trabajo y sean los primeros en lograr vender una compañía colombiana a un fondo en el extranjero o inversionista. Esos lo hemos visto en Brasil y Argentina pero en Colombia aún no.

El punto entonces es que mientras no se den las condiciones para que haya mecanismos de salida, claros, rápidos y con retorno para el inversor el emprendimiento del tipo Silicon Valley en Colombia no va a despegar.

Hay otras consideraciones sobre ese modelo de emprendimiento que creo que son importantes como el enfoque en el producto/servicio más que en hacerse ricos de la noche a la mañana, pero eso es motivo de otro post.

Usando SQL con Entity Framework

Cuando se utiliza Entity Framework con Code First generalmente se utiliza Linq para que el DBContext relacione el linq con el objeto, por ejemplo si quiero un usuario especifico de mi aplicación escribo algo como

using (SecurityEngineDb LAPDb = new SecurityEngineDb())
{
var user = LAPDb.users.Single(p => p.username == userName);
return user;
}

Entonces EF transforma eso en la instrucción Select [Campos] from Users Where UserName = @UserName, etc, etc.
Ahora bien, hay algunas instrucciones SQL que por su complejidad, optimización o la razón que sea no se puede escribir utilizando linq, así que el context también incluye la capacidad de escribir instrucciones SQL, utilizando DBContext.Database.SqlQuery, y a este método le podemos pasar la instruccion SQL y sus parámetros (ya todos sabemos que las instrucciones SQL deben ser parametrizadas para evitar ataques de SQL Injection cierto? pero bueno ese es otro post). El método sqlQuery es un genérico asi que si el entity framework es tan inteligente que se da cuenta que al final el objeto es un usuario o cualquier otra entidad del modelo simplemente lo pongo en el SqlQuery(sqlInstucction, parameters) y voila, tengo unos usuarios que son el resultado de mi complicada instrucción SQL.

Pero y si la instrucción SQL retorna un conjunto de columnas que no corresponden a ninguna de mis clases del modelo? (algo que creo que es muy común, por ejemplo, en reportes), pues hemos visto que una alternativa es declarar esa clase independiente del modelo y utilizarlo como parámetro en el sqlQuery.

Por ejemplo, mi consulta compleja devuelve unos campos que son equivalentes a esta clase:

public class FullfiledTransition
{
public int Requested { get; set; }
public int Fullfilled { get; set; }
public Guid Transition_id { get; set; }
public Guid idSourceActivity { get; set; }
public Guid idTargetActivity { get; set; }
}

puedo definirla sin que quede relacionada con el modelo , es decir no quiero un objeto en la base de datos con esta estructura. y utilizarla con el sqlQuery asi:

var fullfilledTransitions = wfEngineDb.Database.SqlQuery(sb.ToString(), activityInstanceId);
donde sb es el StringBuilder (ya sabemos que siempre hay que concatenar con stringBuilde cierto?) de mi instrucción SQL y activityInstanceId el parámetro que recibe esa instrucción.

es un pequeño truco que ayuda a sacar máximo provecho del EF y su capacidad de ejecutar instrucciones SQL.

Cadenas de Conexion en Entity Framework

En los últimos meses hemos desarrollado en 3Metas varios proyectos utilizando el Entity Framework como modelo de acceso a datos, especialmente me gusta el modelo Code First en los que teóricamente me desentiendo del motor de base de datos y me enfoco en el modelo de objetos, no siempre es tan fluido y a hay que desempolvar el manual de Linq para que tatuárselo en un brazo, pero en general la experiencia ha sido muy buena.

Ahora bien, una de las cosas más interesante del Entity Framework cuando se trabaja con Code First consiste en la capacidad de crear bases de datos que reflejan el modelo y sobre las que se van a almacenar los datos y esto es casi mágico para el desarrollador, pero ya en el ambiente de producción y en aplicaciones corporativas se requiere más control, así que es mejor definir su propia cadena de conexión. Esto resulta un poco complicado la primera vez porque uno siempre se esta preguntando pero como supo EF a donde conectarse, servidor, usuario, nombre de la base de datos, etc.  Revisando la documentación del entity framewor en el objeto DbContext que es de donde se hereda el controlador de la base de datos vemos lo siguiente en el constructor

Constructs a new context instance using conventions to create the name of the database to which a connection will be made. The by-convention name is the full name (namespace + class name) of the derived context class.  See the class remarks for how this is used to create a connection.

y un poco más en la documentación de clase se encuentra lo siguiente:

The Entity Data Model backing the context can be specified in several ways. When using the Code First approach, the System.Data.Entity.DbSet<TEntity> properties on the derived context are used to build a model by convention.   The connection to the database (including the name of the database) can be specified in several ways.  If the parameterless DbContext constructor is called from a derived context, then the name of the derived context is used to find a connection string in the app.config or web.config file. If no connection string is found, then the name is passed to the DefaultConnectionFactory registered on the System.Data.Entity.Database class.

The connection factory then uses the context name as the database name in a default connection string. (This default connection string points to .SQLEXPRESS on the local machine unless a different DefaultConnectionFactory is registered.) Instead of using the derived context name, the connection/database name can also be specified explicitly by passing the name to one of the DbContext constructors that takes a string. The name can also be passed in the form “name=myname”, in which case the name must be found in the config file or an exception will be thrown.

Note that the connection found in the app.config or web.config file can be a normal database connection string (not a special Entity Framework connection string) in which case the DbContext will use Code First.

Que básicamente nos dice que la base de datos se llamara como se llame la clase (incluido el namespace) de donde que fue heredada de DBContext, por ejemplo, si mi clase se llama MyNamespace.MyComponente.MyClase, así se llamara la nueva base de datos en una instancia de SQL que se llame SQLExpress dentro de la maquina en la que esta ejecutándose la Dll. Ahora bien si se quiere definir el nombre de la base de datos se puede invocar el constructor de DBContext asi:

public MTRDB() : base(“MyDB”) { }

Donde MTRDB es el nombre de la clase que esta heredando de DBContext y MyDB es el nombre con el que quiero que se cree la base de datos en la instancia SQLExpress de la maquina local.

Ahora si lo que se quiere es prevenir que EF vuelva a crear la base de datos o que utilice una base de datos existente en otro servidor, con otro nombre, con seguridad de SQL o cualquier combinación de las anteriores se debe crear una llave de tipo Connectionstring en el archivo config (web.config o app.config) de la solución que esta referenciando la clase que heredo de DBContext, esta llave debe tener el mismo nombre de la clase (si no se uso el constructor) o el mismo nombre que se uso en el constructor, por ejemplo y de acuerdo al ejemplo anterior, si la app encuentra una llave de configuración que se llame MyDB utilizará la información de esa cadena de conexión para conectarse a la BD donde espera encontrar los modelos de objetos.

Un detalle importante es que cuando se utilizan cadenas de conexión es bueno incluir el parámetro  MultipleActiveResultSets=True en la cadena de conexión, ya que de no hacerlo el DBContext solo podrá manejar un resultado al tiempo y no permitirá ejecutar otros comandos mientras no se cierre el proceso del anterior. así que algo como esto


using (WFEngineDb wfEngineDb = new WFEngineDb())
{
var fullfilledTransitions = wfEngineDb.Database.SqlQuery<FullfiledTransition>(sb.ToString(), activityInstanceId);
foreach (var fullfilledTransition in fullfilledTransitions)
{
if ((fullfilledTransition.Requested - fullfilledTransition.Fullfilled) == 0)
{
var transition = wfEngineDb.transitions.Find(fullfilledTransition.Transition_id);
transitions.Add(transition);
}
}
}

Generaría un error ya que el find no puede ejecutarse dentro de la operación de consulta a la base de datos. El error seria algo del tipo: There is already an open DataReader associated with this Command which must be closed first.

 La capacidad del EF de distiguir por configuración si estoy en desarrollo o en producción por la presencia o no de la cadena de conexión en el archivo config de la solución nos ha parecido no solo muy útil sino que se ha vuelto parte de nuestro proceso de desarrollo permitiéndonos probar el componente contra múltiples ambientes de una forma muy fácil y rápida.

En uno de nuestros proyectos, por ejemplo,  teníamos una base de datos en producción con más de 70 millones de registros y soportando un web site con picos de hasta un millón de visitantes diarios y el EF se comporto de maravilla (después de crear índices y hacer un tunning juicioso de la base de datos), así que creemos que es una tecnología bastante madura y robusta como para poner rápidamente aplicaciones importantes en producción.

Pd. No soy experto en nhibernate pero me gusta de EF Code First que no hay archivos de configuración ni nada aparte de mi clase para definir el modelo y cuando se necesita algo particular el Dataanotations hace el trabajo muy bien.

 

 

 

 

 

Cambiar Default Schema

Una rápida de Entity Framework + Code First.

Hay ocasiones en las que se quiere crear la BD en otro schema dentro de SQL que no sea el dbo, para ello se puede usar la siguiente instrucción:

modelBuilder.Entity<Settings>().ToTable(“Settings”, schemaName);

sin embargo toda las tablas que hacen relaciones muchos a muchos van a seguir quedando en el schema dbo, asi que hay que usar un truco de fluent API para hacer el ajuste, algo como esto:

modelBuilder.Entity<User>()
.HasMany(p => p.groups)
.WithMany(r => r.users)
.Map(m => m.ToTable(“UsersByGroups”, schemaName));

donde schemaName es una variable en la que he puesto el nombre con el que quiero que quede nombrado el schema.

Tiene algunos efectos colaterales cuando se manejan objetos con herencia pero para la mayoría de los escenarios funciona bastante bien. El equipo de EF ya esta advertido de la necesidad de poder modificar el schema de forma global y trabajan en eso.

 

 

 

Concavo Cocuy 2012

En marzo de 2012, con Fernando Ruiz escale nuevamente el Cóncavo en la Serranía del Cocuy y Guican, Boyacá, Colombia. Por muchas y diversas razones esta ha sido la mejor de todas las escaladas en Alta Montaña, un viaje que no por rápido dejo de ser significativo.

Felipe meets Disney

En Enero del 2012 con Claudia y Felipe visitamos el sur del Estado de la Florida, Miami, Fort Lauderdale y Orlando. Felipe lleva meses hablando de los viajes espaciales, los cohetes y los planetas así que tomamos la decisión de llevarlo a conocer Cabo Cañaveral y que viera por sus propios ojos el tamaño de un cohete y sintiera la emoción del simulador de lanzamiento del programa Apolo. Estando en Orlando visitamos los parques de Sea World y Animal Kingdom que creemos son los más apropiados y en los que más puede disfrutar por su edad. 15 días increibles.