domingo, 27 de noviembre de 2011

jqGrid – Listar Orden Compra (Maestro-Detalle)

 

Introducción

La mayoría de las veces los controles que incluye una herramienta de desarrollo puedo no cumplir con las expectativas que uno busca si quiere alcanzar una interfaz rica que aproveche toda la potencia de desarrollo, es por eso que se debe recurrir a componentes externos.

Esta situación suelo encontrarla al mostrar información en un grid, es por eso que jqGrid es un control ideal para potenciar el desarrollo de la interfaz del usuario en entorno web y además se trata de un componente de libre uso.

Lo único aspecto a tener en cuenta se relaciona con la necesidad de conocer algo de javascript, concretamente jquery y de ser posible invocación a webmethods para recuperar la información del grid.

image

 

Configuración

Para poder hacer uso de jqGrid es necesario introducir en el proyecto algunas librerías de javascript.

Las cuales pueden ser descargadas de la pagina jqGrid

La referencia a estas librerías podrían hacerse de dos formas:

- usando el tag <script> en cada una de las paginas donde se requiera el grid

<script src="Scripts/jquery-1.6.4.min.js" type="text/javascript"></script>
<script src="Scripts/jquery-ui-1.8.16.custom.min.js" type="text/javascript"></script> 

<script src="Scripts/jqGrid/grid.locale-es.js" type="text/javascript"></script>
<script src="Scripts/jqGrid/jquery.jqGrid.min.js" type="text/javascript"></script>
<link href="Scripts/jqGrid/ui.jqgrid.css" rel="stylesheet" type="text/css" />

- o usando ScriptManager.RegisterClientScriptInclude(), esto es útil cuando se quiere registrar librerías para todas las paginas de forma global, aplicándolo en el código de la Master Page

public partial class SiteMaster : System.Web.UI.MasterPage
{
    protected override void OnInit(EventArgs e)
    {

        ScriptManager.RegisterClientScriptInclude(Page, typeof(Page), "jquery", ResolveUrl(@"~/Scripts/jquery-1.6.4.min.js"));
        ScriptManager.RegisterClientScriptInclude(Page, typeof(Page), "jqueryui", ResolveUrl(@"~/Scripts/jquery-ui-1.8.16.custom.min.js"));
        ScriptManager.RegisterClientScriptInclude(Page, typeof(Page), "json2", ResolveUrl(@"~/Scripts/json2.js"));
        
        ScriptManager.RegisterClientScriptInclude(Page, typeof(Page), "gridlocale", ResolveUrl(@"~/Scripts/jqGrid/grid.locale-es.js"));
        ScriptManager.RegisterClientScriptInclude(Page, typeof(Page), "jqgrid", ResolveUrl(@"~/Scripts/jqGrid/jquery.jqGrid.min.js"));

        base.OnInit(e);
    }

}

Al usarse un Master Page este podría verse afectado por la rutas relativas de las paginas, lo que ocasionaría una incorrecta resolución de la url y el acceso a los archivos .js, el método ResolveUrl() nos ayuda a evitar este problema.

 

Definición del grid

Definir el grid con las opciones básicas no es nada difícil, para separar el código de scripting del html de la pagina facilitando así el mantenimiento verán en el ejemplo que he definido 3 .js según la operación de cada uno

En este caso en concreto, se usara el “Grid.js”, el cual define el grid maestro

$("#tbOrders").jqGrid({
    datatype: 'json',
    colNames: ['Fecha Pedido', 'Fecha Solicitud', 'Direccion', 'Ciudad', 'Pais'],
    colModel: [
             { name: 'OrderDate', index: 'OrderDate', width: 100, sortable: false },
             { name: 'RequiredDate', index: 'RequiredDate', width: 100, sortable: false },
             { name: 'ShipAddress', index: 'ShipAddress', width: 250, sortable: false },
             { name: 'ShipCity', index: 'ShipCity', width: 110, sortable: false },
             { name: 'ShipCountry', index: 'ShipCountry', width: 110, sortable: false }
              ],
    height: "300px",
    onSelectRow: function (id) {

        getDetailsOrderByOrder(id);

    }
});

y un grid detalle

$("#tbDetailsOrder").jqGrid({
    datatype: 'json',
    colNames: ['Producto', 'Cantidad', 'Precio'],
    colModel: [
             { name: 'ProductName', index: 'ProductName', width: 250, sortable: false },
             { name: 'Quantity', index: 'RequiredDate', width: 100, sortable: false },
             { name: 'UnitPrice', index: 'UnitPrice', width: 100, sortable: false }
              ],
    height: "200px",
    width:"800px"
});

La configuración es bastante estándar para un uso básico, a partir de aquí hay miles de opciones, pero básicamente se define las columnas (atributo “colNames”), así como también las propiedades de cada columnas como ser el ancho de las mismas.

En el grid maestro además se define un evento, el cual enviara el id de la entidad seleccionada para cargar así el detalle, por supuesto el id que recibe como parámetro es el valor que mas adelante veremos en la estructura json devuelta por el webmethod

 

Definición de los Page Métodos

El siguiente paso será definir la información en el servidor para poder recuperar los registros que cargaran el grid

Para esto se define dos Page Methods en la propia pagina web que implementa los grid (podría usarse una pagina adicional para esta definición)

[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public static string GetOrdersByCustomer(string customer)
{

    var orders = NorthwindData.GetOrdersByCustomer(customer);

    var grid = new
    {
        page = 1,
        records = orders.Count(),
        total = orders.Count(),

        rows = from item in orders
               let orderdate = item.OrderDate.HasValue ? item.OrderDate.Value.ToShortDateString() : ""
               let requireddate = item.RequiredDate.HasValue ? item.RequiredDate.Value.ToShortDateString() : ""
              
               select new
               {
                   id = item.OrderID,
                   cell = new string[]{
                       orderdate,
                       requireddate,
                       item.ShipAddress,
                       item.ShipCity,
                       item.ShipCountry,
                       item.Customers.CompanyName

                   }
               }

    };

    return JsonConvert.SerializeObject(grid);
}

 

la estructura que requiere jqGrid es un tanto especial, y gracias a los métodos anónimos es posible armarla, y como ultimo paso serializarla usando la librería JSON.NET

La estructura es bastante simple, se define la pagina, la cantidad de registros y el total, estos valores son útiles cuando el grid esta paginado, en este caso no implementamos la paginación.

Luego se definen las filas, en donde se transforma la entidad obteniendo un identidicado en el “id”, mas una propiedad “cell” que es en definitiva un array de string con la información de cada columna requiere, es importante en este punto respetar las posiciones en que debe ir cada dato con respecto a las definición de las columnas en el paso anterior.

El mismo proceso se aplica para recuperar los detalles

[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public static string GetDetailsOrdersByOrder(int order)
{

    var orders = NorthwindData.GetDetailsOrdersByOrder(order);

    var grid = new
    {
        page = 1,
        records = orders.Count(),
        total = orders.Count(),

        rows = from item in orders
               select new
               {
                   id = item.OrderID,
                   cell = new string[]{
                       item.ProductsReference.Value.ProductName,
                       item.Quantity.ToString(),
                       item.UnitPrice.ToString("N2")
                   }
               }

    };

    return JsonConvert.SerializeObject(grid);
}

 

Invocar a los Page Methods

Los grid definidos no están conectados de forma directa para que estos invoquen los servicios de datos, sino que se definieron por separado para que uno desde código controle la invocación de los servicios.

En el archivos ServiceInvoke.js se encuentra la definición

function getOrdersByCustomer(customer) {

    var params = new Object();
    params.customer = customer;

    $.ajax({
        type: "POST",
        contentType: "application/json; charset=utf-8",
        url: "Default.aspx/GetOrdersByCustomer",
        data: JSON.stringify(params),
        dataType: "json",
        async: false,
        success: function (data, textStatus) {

            if (textStatus == "success") {

                $("#tbDetailsOrder").clearGridData();

                var grid = $("#tbOrders")[0];
                grid.addJSONData(jQuery.parseJSON(data.d));

            }

        },
        error: function (request, status, error) {
            alert(jQuery.parseJSON(request.responseText).Message);
        }
    });

}

 

Por medio de la línea

$("#tbDetailsOrder").clearGridData();

es que se limpian los registros del grid de detalle, ya que al recargarse el principal ya no hay un registro seleccionado.

function getDetailsOrderByOrder(order) {

    var params = new Object();
    params.order = order;

    $.ajax({
        type: "POST",
        contentType: "application/json; charset=utf-8",
        url: "Default.aspx/GetDetailsOrdersByOrder",
        data: JSON.stringify(params),
        dataType: "json",
        async: false,
        success: function (data, textStatus) {

            if (textStatus == "success") {

                var grid = $("#tbDetailsOrder")[0];
                grid.addJSONData(jQuery.parseJSON(data.d));

            }

        },
        error: function (request, status, error) {
            alert(jQuery.parseJSON(request.responseText).Message);
        }
    });

}

 

Ejemplo de Código


El ejemplo fue desarrollado con visual Studio 2008 y Sql Server 2008 R2 Express

Dentro de la carpeta “DbScript” se encuentra un .sql con la estructura de la db en caso de no poder usar el .mdf adjunto en la solución

 

[C#] 
 

61 comentarios:

  1. Muchas gracias Leandro x el articulo, era justo lo que necesitaba para animarme a empezar a usar jqGrid.
    A propósito de tu articulo y de que esta leyendo algo de información al respecto en Internet me quedan algunas dudas, como por ejemplo con éste articulo
    http://codeasp.net/articles/asp-net/229/using-jqgrid-with-asp-net y si bien es cierto que la paginación y el ordenamiento funcionan correctamente, la configuración de éste ultimo requiere de bastante código(en sql server en un procedimiento almacenado se puede incluir una cadena en la clausula order by??)

    O los mismo demos de jqGrid http://www.trirand.com/blog/jqgrid/jqgrid.html (Loading Data=>JSON Data) que basándome en ellos estoy tratando de acceder a los valores de "sidx" y "sord", en un WebMethod cualquiera de esta manera HttpContext.Current.Request.Form("sidx") pero aparentemente no es posible y creo que por eso optaron x usar Controlador genérico(.ashx), no sé si tendrías idea de xq no puede acceder a ésas variables desde un WebMethod pero si desde un controlador??

    Gracias de antemano

    ResponderEliminar
  2. hola Edalo

    me parece que no puedes acceder al sidx y sord porque esta es informacion que el propio jqgrid genera cuando se renderiza en el cliente
    para estar seguro cuando se carga en el browser el grid ve al codigo fuente del mismo y busca

    es mas si analisas las opciones

    http://www.trirand.com/jqgridwiki/doku.php?id=wiki:options

    veras que en el "prmNames" tienes esta informacion, solo sera cuestion desde jquery tomar la informacion y enviarla por parametro el webmethod

    de forma automatica se enviar en la url, por eso el Request en el handler funcion, lo hace directo el jqgrid
    pero al usar algo personalizado sin tratar la url debes recuperarlo previamente para poder enviarlo

    podrias usar

    var pageoptions = $("#grid").getGridParam("prmNames");

    esto debolvera un array con todas las opciones que intervienen en la paginacion

    si obtienes el sidx, puedes enviarlo en al webmethod


    saludos

    ResponderEliminar
  3. Buenas Leandro, al parecer ya lo tengo funcionando como quería, creo que me deje llevar de los demos del jqGrid (en php) donde los valores de "sidx" y "sord" si se pueden recuperar directamente. ¿Crees que me podrías explicar en breve que hace que un controlador genérico sí pueda tener tener acceso a ésos valores??, tampoco me queda muy claro la parte en la que señalas :"usar algo personalizado sin tratar la url"

    Bueno en cuanto a lo que hice para recuperar los valores de "sidx" y "sord" utilicé : $("#tbDetailsOrder").getGridParam("postData") "postData" contiene los datos necesarios para la ordenación y paginación, "prmNames" sirve para personalizar los nombres de estos valores.

    En cuanto a lo de la ordenación como señalas en el articulo al no estar los grids conectados directamente,como sí sucede en el articulo donde usan un controlador genérico http://codeasp.net/articles/asp-net/229/using-jqgrid-with-asp-net, tengo que invocar manualmente el evento onSortCol http://www.trirand.com/jqgridwiki/doku.php?id=wiki:events y obviamente también modifique los WebMethods : getOrdersByCustomer y getDetailsOrderByOrder agregándole los parámetros necesarios para el ordenamiento y paginación, y eso es más o menos a grandes rasgos lo que tuve que hacer.

    Otra vez muchas gracias Leandro ya hacía varios meses que quería usar jqGrid pero no encontraba un ejemplo práctico en asp.net que me sirviera como punto de inicio en el uso de este plugin y de verdad que en ese sentido tu articulo me ha caído como bajo de cielo :D literalmente

    Saludos

    ResponderEliminar
  4. hola

    Por controlador generico te refieres a un handler ? porque si es asi recuerda que este se comporta similara a una pagina web (puede acceder al request y response) solo que se programa desde codigo (sin un diseñadro html) y se define la extension que usa en el web.config

    en el articulo donde grabo imagenes en uan db los utilizo como medio para obtener estos archivos desde la db y enviarlo en el response


    que bueno que con el postData pudiste recuperar esta informacion para enviar el servicios

    saludos

    ResponderEliminar
  5. Que onda Leandro, oye tengo una duda, fijate que no puedo visualizar al final de la funcion ajax el resultado del post del json, grid.addJSONData(jQuery.parseJSON(data.d)); exactamente ahí. le agregue un alert antes de esa linea y me regresa el siguiente valor {"ID":"1","Name":"ANGEL MARTIN"} alguna idea de ´por que el el grid no me pinte los valores?

    ResponderEliminar
  6. hola Angelito

    no entendi como se relaciona el final de la funcion ajax, con el alert que agregas y en el grid no pinte los valores

    parecieran temas diferentes los que alli planteas, es mas por lo que comentas en el alert recibes un json de respuesta, aunque parece ser un solo item

    saludos

    ResponderEliminar
  7. Ok Leandro, en la funcion getOrdersByCustomer() me imagino que es donde hace la asignacion de los valores devueltos por el webmethod, pero mi grid no muestra los valores devueltos por el json le puse un alert antes de parsear (grid.addJSONData(jQuery.parseJSON(data.d); ) y me muestra lo que te mencionaba antes ( [{"ID":"1","Name":"ANGEL MARTIN"}] ), osea que por el lado del codebehind no tengo problemas. No se si me hace falta algun archivo o alguna version en especifica por las funciones de parseo.

    ResponderEliminar
  8. hola Angelito

    pero esto que mencionas
    [{"ID":"1","Name":"ANGEL MARTIN"}]
    eso es una respuesta json, o sea estas recuperando algo en formato json desde el webmethod

    quizas deberias valida que este webmethod que invocas devuelve la entidad con los datos que necesitas, pero devolver un registro al menso revuelve, por eso que comentas es json

    podrias poner un breakpoint en el webmethod y ver como se crea la entidad que retornas

    saludos

    ResponderEliminar
  9. Es muy buena la publicacion, a mi me sirve para empezar a utilizar este control, a mi me da un poco de cacao al tratar de hacer una pagina sencilla, ya que siempre he practicado en visual basic 6 y me propuse a desarrollar una pagina de lo mas sencilla. La pregunta es si este ejemplo puedo encontrarlo en vb.net

    ResponderEliminar
  10. hola wilfred martinez garcia

    a veces publico articulos tanto en c# como vb.net, pero algunos por la complejidad solo los dejo en el lenguaje del cual son MVP, o sea c#

    igualmente si la idea es usar este control tienes mucho de javascript, mas puntualmente jquery, por lo que vas a tener que aprender la notacion de c#, ya que javascript y c# en la notacion son similares

    por lo tanto conocr vb.net, c# y javascript seguro debas hacerlo
    sin olvidad html

    una recomendacion si vas a ingresar al desarrollo web no seria mejor si comienzas con algo mas basico de asp.net, para aprender conceptos en lugar de arrancar con componentes jquery

    saludos

    ResponderEliminar
  11. hola sss

    tienes una version de libre uso (que puedes descargar y usar como lo hago en el articulo) y una de pago

    pero la version licenciada se relaciona mas con el soporte que por la funcionalidad


    saludos

    ResponderEliminar
  12. Estimado Leandro, muy buen articulo, pero como sería con datos paginados. Quisiera saber eso, porque en el ejemplo prefijas "Page:1" y no veo la lógica para la paginación. Espero tu respuesta gracias.

    ResponderEliminar
  13. hola Anthony

    bueno la verdad no quise complicarlo al ejemplo por eso no pagina

    jqGrid y Asp.net, un primer acercamiento

    si veo de armar algun ejemplo

    saludos

    ResponderEliminar
  14. Estimado Leandro, y para cargar los datos al momento de cargar la página, es decir que muestre datos al cargar la página, sin necesidad de que haga click en el boton "Buscar". ?????????????

    ResponderEliminar
  15. Leandro, te felicito como muchos ya lo han hecho por tu buen trabajo.
    Quiero preguntarte si tienes alguna manera de que el tamaño del grid se ajuste al tamaño de la pantalla. en el ejemplo tu tienes definidos tanto el "width" como el "height". me he fijado y si se pone width:"auto", este toma el tamaño de todo el grid pero no el de la pantalla. puedes ayudarme con esto?? Muchas gracias.

    ResponderEliminar
  16. hola Diego

    La verdad no me puse a evaluar el tema de layout de forma seria,
    pero ya que lo planteas veo que no es tan directo, no al menos si pretendes que se adapte al movimiento del browser

    Possible to make jqGrid stretch to 100%?

    Resize jqGrid when browser is resized?

    dale una mirada a

    jqGrids.fluid extension

    saludos

    ResponderEliminar
  17. hola Anthony

    simplemente invocarias al metodo
    getOrdersByCustomer(), en este caso sin aplicar un filtro

    lo harias directo en la carga de la pagina

    $(function(){
    getOrdersByCustomer('');
    });

    recuerda que
    $(function(){...

    ejecutara el codigo cuando el DOM del html de la pagina se haya cargado completo, alli invocara por $.ajax y cargara el grid

    saludos

    ResponderEliminar
  18. disculpa, como puedo accesar al metodo OnInit? soy nuevo en c#

    ResponderEliminar
  19. hola Omar Gomez

    al evento OnInit del webform ?

    podrias definir

    protected void Page_Init(object sender, EventArgs e){

    }

    saludos

    ResponderEliminar
  20. hola leandro, te ago una pregunta como puedo modificar datos de 5 tablas con linq to sql, cargar se cargan bien pero al momento de modificar ahi dos tablas que me fallan y no se modifican, osea cuando veo los datos en el datagrid no aparecen quedan en blancos. que podria ser.

    ResponderEliminar
  21. hola luis

    el tema es que al actualizar deberias tomar los datos y realziar queries de actualizacion individuales por cada tabla

    o sea puedes armar una query que una todo y lo muestre

    pero despues deberias tomar cada dato he impactar en cada entidad por separado, localizando cada entidad por id o codigo y pasando los cambios

    saludos

    ResponderEliminar
  22. Entonces Leandro...
    Estoy enviando unos parametros al webmethod
    $.ajax({
    url:
    "PaisWF.aspx/Navegar", //PageMethod
    data: "{'pPageSize':'" + $('#Pais_MultiTableDatos').getGridParam("rowNum") + "','pCurrentPage':'" + $('#Pais_MultiTableDatos').getGridParam("page") + "','pSortColumn':'" + $('#Pais_MultiTableDatos').getGridParam("sortname") +
    "','pSortOrder':'" + $('#Pais_MultiTableDatos').getGridParam("sortorder") +
    "'}",

    pero ademas quiero enviar los parametros de busqueda como searchString, searchOper, searchField.. pero no he podido dar con como los puedo enviar.... si me pudieras indicar quedaria muy agradecido.

    ResponderEliminar
  23. hola CCMM

    respondi en el foro

    http://social.msdn.microsoft.com/Forums/es-ES/netfxwebes/thread/bbeb2da4-8670-4608-89ab-fc57af2e47f8

    ResponderEliminar
  24. Hola, he trabajado con el master detail y local funciona genial, pero cuando subo al servidor el grid maestro se ve vacío. qué podrá ser?
    gracias.

    ResponderEliminar
  25. hola Brissa

    es dificil decirlo, quizas algun error que este mal controlado

    podrias usar alguna tool como ser el Developer tools del IE 8 o superiore al cual accedes con la tabla F12

    con este podrias hacer un Profiler de la comunicacion y ver que mensajes se envian, para validar que se reciba el json del grid

    saludos

    ResponderEliminar
  26. Hola leandro,
    Te pregunto, cuando ejecuto la solución y escribo algo en el textbox, me sale este mensaje:
    "Keyword not supported: 'password'."
    PD: Estoy utilizando una inatancia local del SQL.
    Gracias !

    ResponderEliminar
  27. hola Cristian

    que raro ese mensaje
    has puesto un breakpoint en el webmethod he ingresa?

    si lo hace defines un try..catch en el codigo para ver si es un problema del webmethod que falla cuando quiere recuperar la informacion

    has validado el connection string que defines para conectarte a la db, si esta correcto?

    saludos

    ResponderEliminar
  28. Hola leandro,
    Gracias por responder,
    Puse el breack-point, y efectivamente entra al web-metodo AutocompleteCustomer
    El error ocurre en el Designer cuando se instancia este objeto:
    northwindEntities context = new northwindEntities();

    Mira una imagen:

    https://skydrive.live.com/redir?resid=E86EA45CA85C749E!343

    Referente a la cadena de conexión del .config, así me quedo:



    Recuerda que ejecute el script en una instancia completa de SQL y en su efecto creé un usuario que llamé usrNorthwind, el cual tiene permisos db_owner sobre la base de datos ;)

    Gracias !

    ResponderEliminar
  29. Conexión:
    add name="northwindEntities" connectionString="Password=a54321;Persist Security Info=True;User ID=usrNorthwind;Initial Catalog=Northwind;Data Source=C-CPEREZ\SQL2008R2" providerName="System.Data.EntityClient"

    ResponderEliminar
  30. hola Cristian

    la verdad esta bastante raro el error

    pero me pregunto cuando defines la invocacion a la base de northwindEntities, le pasas dos parametros si con uno solo que indique cual es la key del connection string en el config es mas que suficiente

    saludos

    ResponderEliminar
  31. Hola buenas gracias por la info, si alguien puede ayudarme estoy teniendo problemas para pagina una grilla en C# con webservice. el funcionamiento es el siguiente
    al cargar la pagina se carga la grilla.
    luego por medio de un webservice ( no editando desde la grilla) modifico el dato en la BD, el tema es que cuando me devuelve el ok del webservice de dato modificado, no puedo refrescar la grilla sin que mantenga el paginado .

    hay algun ejemplo que cumpla con esto?
    muchas gracias

    ResponderEliminar
  32. hola Maximiliano

    cuando mencionas grilla es que usas el jqGrid, o se trata del GridView de asp.net ?

    porque se supone que al actualizar deberias enviar el nro de la pagina en que te encuentras para recuperar los datos de esta puntualmente

    el webmethod que uses para recuperar la info del grid seguro tiene entre sus parametro el nro pagina que quiere recuperar, ese valor debes asignarlo con el que tienes actualmente

    veras que cuando informo devuelvo los datos del page, records y total, en este caso no tengo paginado pero si lo tuviera alli informaria los datos de que pagina se esta mostrando

    podrias analizar
    jqGrid y Asp.net, un primer acercamiento

    analiza la definicion de de los parametros del webmethod

    saludos

    ResponderEliminar
  33. necesito rellenar un campo de texto al seleccionar un elementod e mi jqgrid pero nose como hacerlo..

    ResponderEliminar
  34. hola Natalia

    quizas esto ayude

    Cell Editing

    lo que veo es que en la definicion de la columan debes poner

    editable:true, edittype:'text'

    para habilitar que esa columan es editable

    saludos

    ResponderEliminar
  35. Hola leandro, estoy haciendo un proyecto y se me ha presentado un inconveniente.

    Codigo
    public string getEventosUsuario(string email2)
    {
    int IdUsuario = usuario.getIdUser(email2);

    List lista = (from eventosUsuario in context.userEvents
    where eventosUsuario.Id_usuario == IdUsuario
    select eventosUsuario.Id_evento).ToList();

    var eventos = context.Events;

    var grid = new
    {
    page = 1,
    records = eventos.Count(),
    total = eventos.Count(),

    rows = from item in eventos
    where lista.Contains(item.Id)
    select new
    {
    id = item.Id,
    cell = new string[]{
    item.nombre,
    item.fecha_ini.ToString(),
    item.fecha_fin.ToString(),
    item.descripcion
    }
    }

    };
    return Newtonsoft.Json.JsonConvert.SerializeObject(grid);
    //var cadena = new JavaScriptSerializer().Serialize(grid);
    //return cadena;
    //string cadena = Newtonsoft.Json.JsonConvert.SerializeObject(records); --Tambien funciona :D

    }

    Error : LINQ to Entities does not recognize the method 'System.String ToString()' method, and this method cannot be translated into a store expression.

    Agradezco su colaboración

    ResponderEliminar
  36. Implemente el ejemplo y al cargar la pagina me deshabilita todo el contenido, como si estuviera en una capa inferior, lo movi a otra pagina y me sucede los mismo... no se donde esta el error...

    ResponderEliminar
  37. hola Sombrerete

    recuerda que cuando usas entity framework todo el link que armes se traduce a un sql

    por lo tanto cuando usas
    var eventos = context.Events;

    no se ejecua ninguna linq, recien lo hace cuando

    rows = from item in eventos ...

    es raro que no dijo nada del Contains() porque tampoco es soportado, pero donde falla es al hacer
    item.fecha_ini.ToString(),

    quizas debas usar
    var eventos = context.Events.ToList();

    esto fuera a traer a memoria todos los eventos, asi depsues usarias linq to object para armar las rows

    saludos

    ResponderEliminar
  38. Error al tratar de serializar la cadena grid, sucede cuando coloco los campos tipo fecha y los quiero pasar a String,
    si quito estos dos campos funciona correctamente


    public string getEventosUsuario(string email2)
    {
    int IdUsuario = usuario.getIdUser(email2);

    var eventos = context.Events;

    var grid = new
    {
    page = 1,
    records = eventos.Count(),
    total = eventos.Count(),

    rows = from items in eventos
    where (from eventosUsuario in context.userEvents
    where eventosUsuario.Id_usuario == IdUsuario
    select eventosUsuario.Id_evento).Contains(items.Id)
    select new
    {
    id = items.Id,
    cell = new List(){
    items.nombre,
    items.descripcion,
    items.fecha_ini.ToString(),
    items.fecha_ini.ToString()
    }
    }


    };

    var cadena2 = Newtonsoft.Json.JsonConvert.SerializeObject(grid);

    return cadena2;
    }

    Error: LINQ to Entities does not recognize the method 'System.String ToString()' method, and this method cannot be translated into a store expression.

    Lo intente hacer de esta otra forma y tampoco funciono

    var grid2 = new
    {
    page = 1,
    records = eventos.Count(),
    total = eventos.Count(),

    rows = (from items in eventos
    where (from eventosUsuario in context.userEvents
    where eventosUsuario.Id_usuario == IdUsuario
    select eventosUsuario.Id_evento).Contains(items.Id)
    select items).Select(o => new
    {
    id = o.Id,
    cell = new List(){
    o.nombre,
    o.fecha_ini.Value.ToString(),
    o.fecha_fin.Value.ToString(),
    o.descripcion
    }
    })


    };

    ResponderEliminar
  39. hola william

    recuerda que al usar entity framework las queries de linq que definas se traducen a sql para eejcutarse contra la db, por lo tanto no puedes usar metodo de .net que no se puedan convertir a una expression sql

    eso es justamente lo que menciona el error, el ToString(), que usas aqui
    o.fecha_ini.Value.ToString(),
    no puede usarlo

    saludos

    ResponderEliminar
  40. Muchas gracias leandro por tu colaboración. Este es el código con el que resolvi el problema :D

    public string getEventosUsuario(string email2)
    {
    int IdUsuario = usuario.getIdUser(email2);

    var eventos = context.Events;


    var grid = new
    {
    page = 1,
    records = eventos.Count(),
    total = eventos.Count(),

    rows = from items in eventos.ToList()
    where (from eventosUsuario in context.userEvents
    where eventosUsuario.Id_usuario == IdUsuario
    select eventosUsuario.Id_evento).Contains(items.Id)
    select new
    {
    id = items.Id,
    cell = new List(){
    items.nombre,
    items.descripcion,
    items.fecha_ini.ToString(),
    items.fecha_fin.ToString(),

    }
    }

    };

    var cadena2 = Newtonsoft.Json.JsonConvert.SerializeObject(grid);

    return cadena2;
    }

    ResponderEliminar
  41. hola william

    ojo que cuando haces
    eventos.ToList()

    estas trayendo la tabla completa a memoria, si son pocos registros no tendras problemas pero si la tabla crece, bueno no creo que sea performante

    saludos

    ResponderEliminar
  42. Hola Leandro, primero felicitaciones por tu blog y seguido a esto queria me des tu opinion sobre como cargar los select de la grilla, ejemplo, segun JQGRID el formato para armar un select debe ser pasado de esta forma Ej. editoptions: { value: “FE:FedEx; IN:InTime; TN:TNT” } y con esta cadena se armaria el select, bien, yo encontre una solucion (no muy elegante) para devolver este formato desde un WebMethod y es la siguiente:

    StringBuilder sb = new StringBuilder();
    sb.Append(":;");
    foreach (var el in RolBLL.ListRol())
    {
    sb.Append(el.ID_Rol);
    sb.Append(":");
    sb.Append(el.Rol);
    sb.Append(";");
    }
    return sb.ToString();

    queria me des tu opinion y saber si conoces alguna otra forma utilizando, por ejemplo, alguna propiedad de JsonConvert que devuleva este formato, gracias! y saludos

    ResponderEliminar
  43. hola Gaston

    pero porque no creaste el objeto usando un entidad anonima y luego la serialzias con json.net

    como lo realizo en este articulo, queda en el codigo mucho mejro que armar algo como string

    saludos

    ResponderEliminar
  44. //Hola Leandro buenas noches y feliz año; como veras aun sigo quebrandome la cabeza porque no puedo llenar mi jqgrid!!

    //tengo 2 proyectos
    //-Datos(DataAccess)
    //-Vista(Forms and WebService)

    //Mi codigo en C#:
    //-Datos

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    namespace Datos
    {
    public class Orders
    {
    public string Id { get; set; }
    public string Name { get; set; }
    public string OrderDate { get; set; }
    public string Employee { get; set; }
    }
    }
    //************************************************
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    using System.Data;
    using System.Data.SqlClient;
    using System.Configuration;

    namespace Datos
    {
    public class Functions
    {
    SqlConnection cn = new SqlConnection(ConfigurationManager.ConnectionStrings["conex"].ConnectionString);
    public List d_GetOrders()
    {
    List list = new List();
    Orders entity;
    string sql = "select OrderID Id,ContactName Name,OrderDate,(FirstName + ' ' + LastName) Employee " +
    "from (Orders o inner join Customers c on o.CustomerID=c.CustomerID) " +
    "inner join Employees e on o.EmployeeID=e.EmployeeID";
    SqlCommand cmd = new SqlCommand(sql, cn);
    cmd.CommandType = CommandType.Text;
    cn.Open();
    SqlDataReader dr = cmd.ExecuteReader();
    while (dr.Read())
    {
    entity = new Orders();
    entity.Id = dr[0].ToString();
    entity.Name = dr[1].ToString();
    entity.OrderDate = dr[2].ToString();
    entity.Employee = dr[3].ToString();

    list.Add(entity);
    }
    cn.Close();
    return list;
    }
    }
    }
    //***********************************************
    //-WebService
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Services;

    using System.Web.Script.Serialization;
    using Datos;
    using System.Web.Script.Services;
    using Newtonsoft.Json;

    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.Web.Script.Services.ScriptService]
    public class WebService : System.Web.Services.WebService {

    public WebService () {
    //InitializeComponent();
    }

    [WebMethod]
    [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
    public string WSGetOrders() {

    Functions obj = new Functions();
    var grid = obj.d_GetOrders();

    var griddata = new
    {
    total ="1",
    page = "1",
    records = "10",
    rows= grid
    };

    return JsonConvert.SerializeObject(griddata);

    }
    }
    //*****************************************************

    ResponderEliminar
  45. //Mi pregunta esta en 2 partes porque el blogger no me permitia !!
    //**********************************************
    //-ASPX
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
    <title>Prueba JQGRID</title>
    <link href="css/jquery-ui-1.9.1.custom.min.css" rel="stylesheet" type="text/css" />
    <link href="css/ui.jqgrid.css" rel="stylesheet" type="text/css" />
    <script src="js/jquery-1.7.2.min.js" type="text/javascript"></script>
    <script src="js/grid.locale-es.js" type="text/javascript"></script>
    <script src="js/jquery.jqGrid.min.js" type="text/javascript"></script>
    <script src="js/jquery-ui-1.9.1.custom.min.js" type="text/javascript"></script>
    <script type="text/javascript">
    $(document).ready(function () {

    $("#list").jqGrid({
    url: "WebService.asmx/WSGetOrders",
    contenttype: "application/json; charset=utf-8",
    datatype: "json",
    data: "{}",
    height: 250,
    colNames: ['Id', 'Name', 'OrderDate', 'Employee'],
    colModel: [
    { name: 'Id', index: 'Id', width: 60 },
    { name: 'Name', index: 'Name', width: 90 },
    { name: 'OrderDate', index: 'OrderDate', width: 100 },
    { name: 'Employee', index: 'Employee', width: 100 }
    ],
    caption: "ORDERS",
    altRows: true
    });

    });
    </script>
    </head>
    <body>
    <table id="list"></table>
    <div id="page"></div>
    </body>
    </html>
    //******************************************************
    //Algunos valores devueltos de json son (mediante un alert lo comprobe):
    {
    "total": "1",
    "page": "1",
    "records": "10",
    "rows": [
    {
    "Id": "10248",
    "Name": "Paul Henriot",
    "OrderDate": "04/07/1996 12:00:00 a.m.",
    "Employee": "Steven Buchanan"
    },
    {
    "Id": "10249",
    "Name": "Karin Josephs",
    "OrderDate": "05/07/1996 12:00:00 a.m.",
    "Employee": "Michael Suyama"
    },
    {
    "Id": "10250",
    "Name": "Mario Pontes",
    "OrderDate": "08/07/1996 12:00:00 a.m.",
    "Employee": "Margaret Peacock"
    },
    {
    "Id": "10251",
    "Name": "Mary Saveley",
    "OrderDate": "08/07/1996 12:00:00 a.m.",
    "Employee": "Janet Leverling"
    },
    {
    "Id": "10252",
    "Name": "Pascale Cartrain",
    "OrderDate": "09/07/1996 12:00:00 a.m.",
    "Employee": "Margaret Peacock"
    }
    ]
    }
    //********************************************************
    //pero mi grdi sigue vacio
    //Mil gracias por la atencion!!!

    ResponderEliminar
  46. hola Franky

    lo que noto es que el web service devuelve el json como string, pero no pones el codigo el evento "success" dodne la linea importante es:

    grid.addJSONData(jQuery.parseJSON(data.d));

    con es alinea estarias asignando el contenido, porque no cargas el grid usando $.ajax u no directo la url en el jqgrid

    es que sino el webservice deberia devolver json de forma directa y no un string

    saludos

    ResponderEliminar
  47. Leandro intente con otro metodo en el cual si los datos estan escritos directamente en el <script> como:
    cadena = [
    { "codigo": "1A", "fecha": "31-07-2014", "nombre": "test", "total": "210.00" },
    { "codigo": "2A", "fecha": "2007-10-02", "nombre": "test2", "total": "320.00" },
    { "codigo": "3A", "fecha": "2007-09-01", "nombre": "test3", "total": "430.00" }
    ];

    Luego
    $("#list").jqGrid({
    datatype: "local",
    data: cadena,.........

    Cargan los datos perfectamente; ahora lo que intente hacer es devolver un string desde webmethod:

    [{"codigo":"10258","fecha":"17-07-1996","nombre":"Roland Mendel","total":"10"},{"codigo":"10270","fecha":"01-08-1996","nombre":"Pirkko Koskitalo","total":"10"},{"codigo":"10275","fecha":"07-08-1996","nombre":"Giovanni Rovelli","total":"10"},{"codigo":"10285","fecha":"20-08-1996","nombre":"Horst Kloss","total":"10"},{"codigo":"10292","fecha":"28-08-1996","nombre":"Anabela Domingues","total":"10"}];

    Y en una funcion generada me esta devolviendo correctamente en string:

    var cadena;
    $.ajax(
    {
    type: "POST",
    url: "WebService.asmx/ObtenerPedidos",
    contentType: "application/json; charset=utf-8",
    dataType: "json",
    success: function (response) {
    cadena = response.d;
    alert(cadena);
    },
    error: function (result) {
    alert('ERROR ' + result.status + ' ' + result.statusText);
    }
    });

    Ahora como haria para pasar ese string como los valores del jqgrid, gracias.

    ResponderEliminar
  48. hola Franky

    tiene que usar el

    grid.addJSONData(jQuery.parseJSON(data.d));

    para pasar ese jason al grid

    saludos

    ResponderEliminar
  49. Hola Leandro,
    yo estoy usando jqgrid con php y sql server 2008,

    pero como puedo realizar busquedas por fechas y que muestren en una grilla.

    ResponderEliminar
  50. Hola Leandro,
    yo estoy usando jqgrid con php y sql server 2008,

    pero como puedo realizar busquedas por fechas y que muestren en una grilla.

    ResponderEliminar
  51. hola Michael

    la verdad ninca programe con PHP
    imagino que debe tener librerias para poder conectarte a la db y ejecutar una query

    pero no estoy seguro como se lo enviarias al jqgrid, quizas podrias hacer una pagina php que se conecte a la db y devuelva el json, y esta pagina la usas en la url del jqgrid

    saludos

    ResponderEliminar
  52. Buenas tardes leandro acudo a ti como ultimo recurso jajajaja disculpaaaaaaaa mi duda es la siguiente yo lleno mi jqgrid dependiendo de la opcion que seleccionan en un select, el problema es que el grid solo se carga la primera vez que selecciono una opcion, la segunda ya no se actualiza con los nuevos datos que escogio el usuario

    tengo el armado de mi jqgrid asi mira:

    function CreaGrid(datos) {
    $(function () {
    var grid = jQuery('#GridProve');
    grid.jqGrid({
    data: jQuery.parseJSON(datos),
    datatype: 'local',
    height: 200,
    hidegrid: false,
    rowNum: 10,
    viewrecords: true,
    caption: 'Proveedores',
    pager: '#pager',
    colNames: ['ID', 'Proveedor', 'Convenio'],
    colModel: [
    { name: 'IDProve', index: 'IDProve', width: 100, align: 'center', sorttype: 'int', hidden: true },
    { name: 'StrNombreProve', index: 'StrNombreProve', width: 200, align: 'left', sorttype: 'int' },
    { name: 'BooConvenio', index: 'BooConvenio', width: 100, align: 'center', formatter: 'checkbox', stype: 'select', searchoptions: { sopt: ['eq'], value: ':Todos;true:Con Convenio;false:Sin Convenio'} }
    ],
    onSelectRow: function (id) {
    ObtenerDetalleProveedor(id);
    }
    });
    grid.jqGrid('filterToolbar', { stringResult: true, searchOnEnter: false, defaultSearch: 'cn' });
    });


    el select llama al webmethod mediante ajax y le regresa al ajax el json si el resultado es success mando a llamar a la funcion que te coloque arriba, la variable datos es la que me trae el nuevo json para cargar los nuevos datos, pero no se actualiza, que estoy haciendo mal de antemano muchas gracias..

    ResponderEliminar
  53. ya encontre la solucion seeeeeeee!!!

    Me quedo asi

    //lIMPIA LOS REGISTROS ANTERIORES
    $("#GridProve").clearGridData();
    //ASIGNA LOS NUEVOS DATOS AL JGGRID
    $('#GridProve').setGridParam({ data: jQuery.parseJSON(datos) }).trigger('reloadGrid');

    desconocia que tenia que hacer esto para asignar nuevos dantos creia yo que al crear el grid la variable jalaria siempre los datos del constructor pero no es asi con el metodo 'setGridParam' agregas los nuevos datos y como tu bien mencionas arriba el metodo clearGridData limpia los anteriores..

    De ante mano muchas gracias ya estaba desesperado con esta cosa pero al fin ya quedoo espero y les sirva a las personas que este haciendo lo mismo que yo saludos...

    ResponderEliminar
  54. como obtener los valores del Tag
    en un treeview?

    lleno el treeview y en cada nodo con CapaEntidades.Clientes=new CapaEntidades.Clientes();

    Clientes.IdCliente=1;
    MiNodo.Tag=Clientes;

    ResponderEliminar
  55. hola Jose

    no entendi, a que treeview haces referencia?

    este articulo trata sobre jqgrid

    saludos

    ResponderEliminar
  56. Buenas, lo primero muchas gracias por el post.
    Mi duda trata sobre la conversión de un dataSet a Json en .net , pero siendo este Json válido para utilizarlo con Jqgrid.
    Gracias, un saludo!

    ResponderEliminar
    Respuestas
    1. hola
      no creo que sea buena idea convertir un dataset a json, quizas deberias convertir los datos a una clase que tu definas como entidad, y usar un List<>
      entonces esta lista si puedes serializarla a json usando json.net
      saludos

      Eliminar