sábado, 28 de abril de 2012

Error al Importar la base de datos de CRM en SQL Server Standar Edition


Muchas veces para "llevarnos" un CRM de un servidor a otro, lo hacemos directamente a través de un backup de la base de datos SQL Server.
Básicamente consiste en hacer un backup normal de la base de datos en el servidor SQL Server del CRM, y restaurarla en el servidor SQL del CRM de destino.

Luego simplemente se importa con el Administrador de implementaciones de CRM, y listo, hemos movido una implantación de CRM.

En la "vida real" nos encontramos con escenarios que nunca son como los ideales o como los esperamos.
Existe un error documentado por la gente de soporte de Microsoft que impide imporar un backup de un Base de datos SQL Server Enterprise en una de version Standar.

Básicamente nos da un error commo el siguiente
Restore failed for Server 'SQLServerName'.


Additional information:


An exception occurred while executing a Transact-SQL statement or batch. (Microsoft.SqlServer.ConnectionInfo)


Database 'Org_MSCRM' cannot be started in this edition of SQL Server because it contains a partition function 'AuditPFN'. Only Enterprise edition of SQL Server supports partitioning. Database 'Org_MSCRM' cannot be started because some of the database functionality is not available in the current edition of SQL Server. (Microsoft SQL Server, Error: 905)
 
Este error puede ser resuelto mediante la ejecución de un Script antes de hacer el backup de la Base de datos.
Para más información hacerca de este error ir a Soporte de Microsoft a esta URL:
http://support.microsoft.com/kb/2567984

jueves, 26 de abril de 2012

Subcuadrículas avanzadas en formularios de entidades

En CRM 2011 existe una funcionalidad que permite añadir "subgrids" dentro de los formularios de las entidades.
Estos "subgrids" pueden enseñar información de registros relacionados, pero solamente de registros relacionados a un subnivel. Esto era así, hasta el UR7.
Con el UR7, existe una posibilidad para poder ver en un subgrid no solamente registros "hijos" sino tambien "nietos", o mas profundos.

Existe un ejemplo en el blog del equipo de CRM:
http://blogs.msdn.com/b/crm/archive/2012/04/16/deep-queries-for-subgrids.aspx

Básicamente consiste e crear el "subgrid", y luego exportar el XML de personalizaciones. En este fichero hay un FetchXML que puede ser modificado para hacer una consulta un poco mas compleja.

Para esto es necesario tener conocimientos de FetchXML.

Un saludo,

sábado, 7 de abril de 2012

xrmservicetoolkit: una gran librería de Javascript para CRM 2011

Periódicamente hago unas búsquedas en CodePlex para encontrar cosas nuevas, herramientas o ideas que puedan ser de utilidad.
Hoy he encontrado un nuevo proyecto publicado por Qiming Jaimie Ji (http://jaimiescode.blogspot.com.es/).
Se trata de una librearía de Javascript (básicamente, un fichero .js) que puede ser descargado de aquí:
http://xrmservicetoolkit.codeplex.com/

Lo bueno de esta librería es que me ha gustado mucho en "enfoque" que le dan, además de agradecer mucho que esta todo súper comentado y explicado.

La clase "XrmServiceToolkit", contiene a su vez 3 clases:
  • .Common: contiene métodos comunes en el trabajo con javascript en CRM 2011, por ejemplo habilitar, ocultar,  cambios de requeridos/opciones de campos, etc.
  • .Rest: métodos CRUD utilizando el servicio REST (OrganizationData.svc)
  • .Soap: métodos CRUS utilizando el servicio SOAP de CRM 2011
Ejemplo de utilización (y comparativa entre REST y SOAP):
test("Test XrmServiceToolkit.Soap.Create() method to create a CRM record (contact)", function () {

            var createContact = new XrmServiceToolkit.Soap.BusinessEntity("contact");
            createContact.attributes["firstname"] = "Diane";
            createContact.attributes["lastname"] = "Morgan";
            createContact.attributes["middlename"] = "<&>";   // Deliberate special characters to ensure that the toolkit can handle special characters correctly.
            createContact.attributes["gendercode"] = { value: 2, type: "OptionSetValue" };
            createContact.attributes["familystatuscode"] = { value: 1, type: "OptionSetValue" }; // Picklist : Single - 1
            createContact.attributes["creditlimit"] = { value: 2, type: "Money" };
            createContact.attributes["birthdate"] = birthDate;
            createContact.attributes["donotemail"] = true;
            createContact.attributes["donotphone"] = false;
            createContact.attributes["parentcustomerid"] = { id: accountId, logicalName: "account", type: "EntityReference" };

            contactId = XrmServiceToolkit.Soap.Create(createContact);

            ok(guidExpr.test(contactId), "Creating a contact should returned the new record's ID in GUID format. ");

});
test("Test XrmServiceToolkit.Rest.Create() method to create a new record", function () {

            var account = {};
            account.Name = "Test Account Name";
            account.Description = "This account was created by the XrmServiceToolkit.Rest.Create() sample.";
            if (contactId != null) {
                //Set a lookup value
                account.PrimaryContactId = { Id: contactId, LogicalName: "contact" };
            }
            //Set a picklist value
            account.PreferredContactMethodCode = { Value: 2 }; //E-mail

            //Set a money value
            account.Revenue = { Value: "2000000.00" }; //Set Annual Revenue

            //Set a Boolean value
            account.DoNotPhone = true; //Do Not Allow

            //Add Two Tasks
            var today = new Date();
            var startDate = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 3); //Set a date three days in the future.

            var LowPriTask = { Subject: "Low Priority Task", ScheduledStart: startDate, PriorityCode: { Value: 0} }; //Low Priority Task
            var HighPriTask = { Subject: "High Priority Task", ScheduledStart: startDate, PriorityCode: { Value: 2} }; //High Priority Task
            account.Account_Tasks = [LowPriTask, HighPriTask];
            XrmServiceToolkit.Rest.Create(
                account,
                "AccountSet",
                function (result) {
                    accountId = result.AccountId;
                    ok(guidExpr.test(result.AccountId), "Creating a account should returned the new record's ID in GUID format. ");
                },
                function (error) {
                    equal(true, false, error.message);
                },
                false
            );
});

La publico porque me parece que tiene una forma súper sencilla de utilizar, y que es de muy fácil evolución.

un saludo,