martes, 28 de septiembre de 2010

Formatos de datos en CRM


Si bien en CRM al hacer consultas a través de la plataforma ya nos devuelve los datos formateados según los datos del usuario que realiza las consultas, muchas veces es necesario recoger esa configuración del usuario para presentar la información según su formato.
De esta forma podremos hacer que nuestros desarrollos sean totalmente "multiformato" y que este se recoja dinámicamente desde el CRM.
Para esto existe una función de SQL Server que provee el CRM que se llama de la siguiente forma:
SELECT * FROM dbo.fn_GetFormatStrings()
Esta función esta documentada en la SDK y se puede llamar de forma soportada. Para mas información acerca de esta función ir a: http://msdn.microsoft.com/en-us/library/bb955087.aspx
Esto devuelve una serie de datos relacionados con el usuario que realiza la consulta (con la autenticación de Windows Integrada) que nos servirán para luego formatear cualquier tipo de dato.
Esto nos devuelve por ejemplo:
  • DateFormat: dd\/MM\/yyyy
  • TimeFormat: hh\:mm tt
  • NumberLanguageCode: en-GB
  • CalendarType: Gregorian
  • NumberFormat_0_Precision: ###,###,###,##0;-###,###,###,##0;0
  • NumberFormat_2_Precision: ###,###,###,##0.00;-###,###,###,##0.00;0.00
  • CurrencyFormat_0_Precision: "£"###,###,###,##0;-"£"###,###,###,##0;"£"0
  • CurrencyFormat_2_Precision: "£"###,###,###,##0.00;-"£"###,###,###,##0.00;"£"0.00
Entonces estos resultados podemos usarlos en C# para formatear datos, por ejemplo:
DateTime dtfecha = new DateTime(2010, 1, 1);
double dblNumero = 587125635.66;

Console.WriteLine(dtfecha.ToString(@"dd\/MM\/yyyy"));
Console.WriteLine(dblNumero.ToString(@"###,###,###,##0;-###,###,###,##0;0"));
Console.WriteLine(dblNumero.ToString(@"""£""###,###,###,##0.00;-""£""###,###,###,##0.00;""£""0.00"));
Esto nos devuelve:

Y listo! de esta simple manera, dejaremos nuestros desarrollos en multiformato recogiéndo los mismos desde el CRM.

un abrazo 

viernes, 24 de septiembre de 2010

Publicado el Rollup 13

En estos "movidos" días con noticias acerca del CRM 2011, se podría pensar que se esta dejando olvidado al "viejo?" Dynamics CRM 4.0.
Pues nada mas lejos de la realidad, ayer el equipo de desarrollo de Microsoft ha publicado un nuevo Rollup (y ya van 13!!).
Como siempre es mejor probar toda nuestra implementación en un servidor de desarrollo antes de instalar los servidores de producción.
Como nota destacable se recoge la compatibilidad con Internet Explorer 9 Beta (http://www.microsoft.com/ie).

un Saludo

miércoles, 15 de septiembre de 2010

Buenas prácticas con los metadatos

Casi siempre en nuestros desarrollos necesitamos ir a los metadatos del CRM, para ver determinados atributos, tamaños, personalizaciones, etc.
Esto nos hará nuestros desarrollos mas dinámicos y adaptables, además de ser mas "inteligentes".
Para esto hay varias formas de acceder a los metadatos, y es necesario que se haga de una forma que afecte lo menos posible al rendimiento tanto de nuestro desarrollo como del servidor de CRM.
Es por esto que me pregunté que diferencias de rendimiento podría haber si en vez de recoger un atributo mediante el mensaje "RetrieveAttribute", recojo la entidad completa mediante el mensaje "RetrieveEntity" o incluso recogiendo todas las entidades con el "RetrieveAllEntities".
Para esto me desarrollé la siguiente aplicación de consola que me muestra las diferencias de tiempos de respuesta:
CrmAuthenticationToken token = new CrmAuthenticationToken();
            token.OrganizationName = "AdventureWorks";

            token.AuthenticationType = 0;

            MetadataService metadataService = new MetadataService();
            metadataService.Url = "http://192.168.1.22:5555/MSCRMServices/2007/MetadataService.asmx";
            metadataService.CrmAuthenticationTokenValue = token;
            metadataService.Credentials = new System.Net.NetworkCredential("usuario", "contraseña", "CRM");
            
            RetrieveAllEntitiesRequest allEntitiesRequest = new RetrieveAllEntitiesRequest();
            allEntitiesRequest.RetrieveAsIfPublished = false;
            allEntitiesRequest.MetadataItems = MetadataItems.EntitiesOnly;

            DateTime dtinicioall = DateTime.Now;
            RetrieveAllEntitiesResponse allEntitiesResponse = (RetrieveAllEntitiesResponse)metadataService.Execute(allEntitiesRequest);
            TimeSpan dtall = DateTime.Now.Subtract(dtinicioall);
            Console.WriteLine("Tiempo en ejecutar RetrieveAllEntitiesResponse:"+dtall.TotalMilliseconds.ToString());

            RetrieveEntityRequest entityRequest = new RetrieveEntityRequest();
            entityRequest.RetrieveAsIfPublished = false;
            entityRequest.LogicalName = "contact";
            entityRequest.EntityItems = EntityItems.All;

            DateTime dtiniciocontact = DateTime.Now;
            RetrieveEntityResponse entityResponse = (RetrieveEntityResponse)metadataService.Execute(entityRequest);
            TimeSpan dtcontact = DateTime.Now.Subtract(dtiniciocontact);
            Console.WriteLine("Tiempo en ejecutar RetrieveEntityResponse de contact:" + dtcontact.TotalMilliseconds.ToString());


            DateTime dtinicioaccount = DateTime.Now;
            entityResponse = (RetrieveEntityResponse)metadataService.Execute(entityRequest);
            TimeSpan dtaccount = DateTime.Now.Subtract(dtinicioaccount);
            Console.WriteLine("Tiempo en ejecutar RetrieveEntityResponse de account:" + dtaccount.TotalMilliseconds.ToString());


            RetrieveAttributeRequest attributeRequest = new RetrieveAttributeRequest();
            attributeRequest.EntityLogicalName = "contact";
            attributeRequest.LogicalName = "firstname";
            attributeRequest.RetrieveAsIfPublished = false;

            DateTime dtiniciofirstname = DateTime.Now;
            RetrieveAttributeResponse attributeResponse = (RetrieveAttributeResponse)metadataService.Execute(attributeRequest);
            TimeSpan dtfirstname = DateTime.Now.Subtract(dtiniciofirstname);
            Console.WriteLine("Tiempo en ejecutar RetrieveAttributeResponse de firstname de contact:" + dtfirstname.TotalMilliseconds.ToString());


            attributeRequest = new RetrieveAttributeRequest();
            attributeRequest.EntityLogicalName = "account";
            attributeRequest.LogicalName = "name";
            attributeRequest.RetrieveAsIfPublished = false;

            DateTime dtinicioname = DateTime.Now;
            attributeResponse = (RetrieveAttributeResponse)metadataService.Execute(attributeRequest);
            TimeSpan dtname = DateTime.Now.Subtract(dtinicioname);
            Console.WriteLine("Tiempo en ejecutar RetrieveAttributeResponse de name de account:" + dtname.TotalMilliseconds.ToString());

            Console.ReadLine();

Bien, esto me devuelve como resultado lo siguiente (los tiempos están en milisegundos):


Lo que se recoge claramente allí es que por ejemplo es mucho mas óptimo el recoger un solo atributo que recoger toda la entidad de "account", pero que pasaría si tenemos que recoger 15 atributos diferentes de "account"?. Allí ya nos convendría recoger la entidad completa...

Conclusión: es claramente recomendable el ejecutar los mensajes mas "ajustados" a lo que se quiera realizar, pero teniendo en cuenta la escalabilidad de nuestra aplicación, y el funcionamiento que se quiere como resultado.

Un abrazo,

jueves, 9 de septiembre de 2010

La beta del CRM 2011 ya está aquí!

Pues sí, por fin! ya podemos tocar lo que será el próximo CRM y ver en primera persona todo lo nuevo.
Se acabaron los foros, comentarios, videos y presentaciones, ahora nos toca a nosotros vivirlo!
La versión Beta ya está disponible para su descar de http://www.crm2011beta.com/

Entren a ver que tal, y participen en los foros para enviar posibles cambios, incidencias, etc (tengan en cuenta que es beta,je).

Por mi parte ya puedo decir que sí:
 "I'm ready for Microsoft Dynamics CRM 2011"



un saludo

lunes, 6 de septiembre de 2010

Como funciona la eliminación de un valor de un Picklist

En este post intentaré explicar lo que ocurre cuando se elimina un valor de un atributo de tipo "Picklist" (desplegable).
Es un poco curioso el funcionamiento, incluso un poco incompleto para mi gusto.
Vamos a ver un ejemplo e iremos revisando como queda la información en el SQL Server.
Primero vamos a crear un atributo nuevo en la entidad de "Caso" y lo añadimos al formulario. Será un desplegable con el nombre "new_categoria" con los valores "Uno", "Dos", "Tres":
Atributo picklist

Creamos un registro de "Caso" con el valor de Categoría en "Dos" y luego hacemos un par de consultas en el SQL Server para ver que nos queda almacenado físicamente en la base de datos y en la FilteredView:

SELECT * FROM IncidentExtensionBase
SELECT incidentid,New_Categoria,New_Categorianame FROM FilteredIncident

Resultados consulta

Hasta ahora, todo normal, ahora bien, imaginemos que necesitamos eliminar el valor del desplegable "Dos". Al eliminarlo nos aparece el siguiente mensaje:
"Si algún registro usa el valor que va a eliminar, actualice el registro de modo que use otro valor para poder guardar este cambio. Una vez quitado este valor, no puede usarlo para buscar este registro en la aplicación. ¿Desea continuar?"

Al leerlo parecería ser que lo que va a hacer será reemplazar los registros con este valor y dejarlo en NULL, pero en realidad no es así.
Borramos el valor y volvemos a hacer la misma consulta que antes:
Resultados consulta 2

Como se ve, en realidad en la base de datos seguimos teniendo el mismo valor, pero lo que ocurre, es que no puede recoger el texto del valor en la FilteredView, cosa que es normal ya que el valor se ha eliminado.

Imagínense que pasado el tiempo, añadimos un nuevo valor en este desplegable con el mismo valor (2) como índice, pero con otro texto que significa otra cosa:
Atributo Picklist 2

Volvemos a hacer la consulta y obtenemos:
Resultados Consulta 3

Con esto sacamos como consecuencia, que al eliminar un valor de un desplegable, los registros relacionados con este valor, siguen teniendo el mismo, y no se eliminan, de hecho si hacemos una búsqueda avanzada por ese atributo filtrando por que "Contiene datos", lo encontrará ya que tiene datos, pero es un dato "inexistente". Además hay que tener en cuenta que si creamos nuevos elementos en el desplegable en índices ya existentes, podríamos estar reemplazando y modificando un valor antiguo que ya no nos interesaba.

La conclusión final y consejo que dejo es que se tenga mucho cuidado con los desplegables y en especial al eliminar los valores, creo que sería una buena práctica no permitir a usuarios finales gestionar este tipo de atributos.

Un abrazo

viernes, 3 de septiembre de 2010

Primera visión interactiva de CRM 2011

xrmvirtual
Julie Yack va a hacer una demostración del nuevo CRM 2011 antes de que salga la versión Beta (prevista para este mes).
La sesión está prevista para el próximo martes 7 de septiembre a las 18:00 hs (hora de España).

Sin duda es un momento esperado! finalmente se empezará a ver de forma abierta el nuevo CRM!

Para mas información ver el blog del equipo de CRM:
http://blogs.msdn.com/b/crm/archive/2010/09/01/your-first-interactive-look-at-crm-2011.aspx

un saludo