viernes, 10 de abril de 2015

Linq EF

Un poquito de Linq, pero Linq usado con Entity. La web está llena de ejemplos como si fuera consultas a sql y cuando se quiere usar como una lista de objetos los ejemplos no abundan tanto.
Lo primero mi clase


Public Class User
    Private _id As String
    Private _nombre As String
    Private _class As String
    Public Property Clase() As String
        Get
            Return _class
        End Get
        Set(ByVal value As String)
            _class = value
        End Set
    End Property
    Public Property ID() As String
        Get
            Return _id
        End Get
        Set(ByVal value As String)
            _id = value
        End Set
    End Property
    Public Property Nombre() As String
        Get
            Return _nombre
        End Get
        Set(ByVal value As String)
            _nombre = value
        End Set
    End Property
End Class
Luego lo rellenamos método clásico


        Dim lst As List(Of User) = New List(Of User)
        lst.Add(New User() With {.ID = 1, .Nombre = "Ana1", .Clase = "A"})
        lst.Add(New User() With {.ID = 2, .Nombre = "Ana2", .Clase = "B"})
        lst.Add(New User() With {.ID = 3, .Nombre = "Ana3", .Clase = "A"})
        lst.Add(New User() With {.ID = 4, .Nombre = "Ana4", .Clase = "B"})
        lst.Add(New User() With {.ID = 5, .Nombre = "Ana5", .Clase = "A"})
        lst.Add(New User() With {.ID = 6, .Nombre = "Ana6", .Clase = "B"})
        lst.Add(New User() With {.ID = 7, .Nombre = "Ana7", .Clase = "A"})
        lst.Add(New User() With {.ID = 8, .Nombre = "Ana8", .Clase = "B"})
        lst.Add(New User() With {.ID = 9, .Nombre = "Ana9", .Clase = "A"})
        lst.Add(New User() With {.ID = 10, .Nombre = "Ana10", .Clase = "B"})
        Dim frutas() As String = {"manzana", "plantano", "fresa", "pera", "melon", "sandia"}
     Dim Precios() As Integer = {5, 6, 7, 8, 9, 10}

     Dim objRet As User

     Dim sRet As String
     Dim iRet As String
Y ahora lo interesante lo ejemplos..
Single


        objRet = lst.Single(Function(x) x.ID = 1)
        sRet = frutas.Single(Function(x) x = "pera")
        iRet = Precios.Single(Function(x) x = 5)
        Console.WriteLine(objRet.Nombre) ' Ana1
        Console.WriteLine(sRet) 'pera
        Console.WriteLine(iRet) '5
        Try
            ' no existe - Exception La secuencia no contiene ningún elemento coincidente
            objRet = lst.Single(Function(x) x.ID = 11)
            sRet = frutas.Single(Function(x) x = "peras")
            iRet = Precios.Single(Function(x) x = 4)
        Catch ex As Exception

        End Try

SingleOrDefault


Try
            objRet = lst.SingleOrDefault(Function(x) x.ID = 11)  '=> nothing
            sRet = frutas.SingleOrDefault(Function(x) x = "peras") '=> nothing
            iRet = Precios.SingleOrDefault(Function(x) x = 4)  ' => 0
            Console.WriteLine(objRet.Nombre) '  Exception
            Console.WriteLine(sRet) ' no falla porque imprime ''
            Console.WriteLine(iRet) ' 0
        Catch ex As Exception

        End Try
 
Mi problema está con el objeto, no quiero un nothing quiero el objeto. Alguno más tiene o ha tenido el mimos problema .

Así que olvida el SingleOrDefault , FirstOrDefault , LastOrDefault porque los resultado serán los mismo

objRet = lst.Where(Function(x) x.ID = 11).DefaultIfEmpty(New User()).First()  '=> Objeto
sRet = frutas.Where(Function(x) x = "peras").DefaultIfEmpty("Juan").First() '=> "Juan"
iRet = Precios.Where(Function(x) x = 4).DefaultIfEmpty(999).First()  ' => 999
Console.WriteLine(objRet.Nombre) ' 
Console.WriteLine(sRet) ' Juan
Console.WriteLine(iRet) '  999

Ahora otra curiosidad, que pasa cuando en una lista hacemos un group by. ¿Cómo se recorren los resultados? 


Try
            Dim lstAgrupado As IEnumerable(Of IGrouping(Of String, User)) = lst.GroupBy(Function(x) x.Clase)
            Dim lstAgrupado2 = lst.GroupBy(Function(x) x.Clase)
            '  Quiero saber cuantos grupos me salieron
            Console.WriteLine("Lista de grupos ")
            For Each sgrupo In lstAgrupado
                Console.WriteLine(sgrupo.Key)
            Next
            Console.WriteLine(" Fin: Lista de grupos")
            'Quiero todos los valores ( vale es un tonteria que ya los tenia en la lista inicial)
            Console.WriteLine("Lista de valores ")
            For Each sgrupo In lstAgrupado.SelectMany(Function(x) x)
                Console.WriteLine(sgrupo.Nombre)
            Next
            Console.WriteLine("Fin : Lista de valores ")
            Console.WriteLine("Todo junto ")
            For Each sgrupo In lstAgrupado
                Console.WriteLine("Key:" & sgrupo.Key)
                For Each sMigrupo In lstAgrupado.Single(Function(x) x.Key = sgrupo.Key)
                    Console.WriteLine(sMigrupo.Nombre)
                Next
                Console.WriteLine("Fin")
            Next
            Console.WriteLine("Fin: Todo junto")
        Catch ex As Exception

        End Try



Y adjunto la imagen de salida

viernes, 20 de marzo de 2015

IN con varibles Sql Server

En un procedimiento almacenado queremos hacer una consulta del tipo

Select * from mitabla where id in (@misValores)

Donde @misValores es dinámico. Hacer un concat en @misValores no funciona

Pero tienes dos soluciones :
  • Solución 1 , con una sentencia dinámica


    DECLARE @misValores2 VARCHAR(MAX)
    SET  @misValores2  = '3,4,22,6014'
    DECLARE @sql NVARCHAR(MAX)
    SET    @sql= 'Select * from mitabla where id in (@ ('+@misValores2 +')'
    EXEC sp_executesql @sql


  • Solución 2 , una variable de tipo tabla

    DECLARE @misValores TABLE (ID INT )
    INSERT INTO @misValores VALUES (3) ,(4),(22),(60),(14)
    SELECT * FROM miTabla  WHERE  id  in ( SELECT ID FROM @misValores )

jueves, 19 de marzo de 2015

Magic String

Hace poco escribí un post, para evitar comparar por un “algo” en código. Sinceramente el código que compara un string con el contenido de una cadena, es una chapuza. Todos lo hemos hecho, normalmente por prisas. Y cuando te toca cambiar el valor de esa cadena, te das cuenta del error que cometiste.

Pues resulta que comprar con un “algo” es un practica que tiene nombre Magic String. Con ese nombre parece hasta genial usarlo.

Pero si lo vas a usar, porque lo necesitas si o si, piensa que hay opciones .

http://geeks.ms/blogs/lruiz/archive/2015/02/05/clean-code-evitando-magic-strings.aspx

http://blog.goyello.com/2014/12/30/magic-strings-no-more/

http://www.variablenotfound.com/2009/12/t4-el-talisman-contra-las-cadenas.html

viernes, 13 de marzo de 2015

Google avisa

Necesitas que la web se vea bien en moviles

Para usuario de blogger esto no sea un problema: las propias plantillas ya realizan los cambios necesarios.
De he hecho lo he con el mio y sin problemas

Pero si tu web es comercial será mejor que te pongas la pilas. Posiblemente no sea fácil, o por lo menos no tan fácil como cambiar unos css

Info
http://communityanalisis.com/google-avisa-sin-version-responsive-desapareces-el-21-de-abril/

Google

http://googlewebmastercentral.blogspot.co.nz/2015/02/finding-more-mobile-friendly-search.html

Utils
https://www.google.com/webmasters/tools/mobile-friendly/

Pero hay más avisos 

Algunas aplicaciones y sitios web utilizan OpenID 2.0 para la autenticación al iniciar sesión y para acceder a los datos a los que hayas concedido permiso de acceso. OpenID 2.0 se ha sustituido por OpenID Connect. A partir 20 de abril de 2015, OpenID 2.0 dejará de estar disponible para Cuentas de Google.

viernes, 6 de marzo de 2015

Nombre de una propiedad


Vale odio ver en el código: dependencias con el contenido de un string. Me desespera.
Siempre que puedo uso enumerados  constantes.. y esta vez no sería diferente.

Quería conocer en cadena el nombre de una propiedad
Es decir miobj.DNI Obtener "DNI"


Imports System.Linq.Expressions

Private Sub Prueba(sender As System.Object, e As System.EventArgs)
        Dim miobj As miClase = New miClase() With {.DNI = "numero pasaporte", .Nombre = "mi nombre completo"}
        Dim nombrePropiedad As String = GetPropertyName(Function() miobj.DNI)
        Console.Write(nombrePropiedad) 'DNI
        Dim nombrePropiedad2 As String = GetPropertyNameB(Function(myObj As miClase) myObj.Nombre)
        Console.Write(nombrePropiedad2) 'Nombre
    End Sub

    Public Shared Function GetPropertyName(Of T)(ByVal expression As Expressions.Expression(Of Func(Of T))) As String
        Dim memberExpression As Expressions.MemberExpression = DirectCast(expression.Body, Expressions.MemberExpression)
        Return memberExpression.Member.Name
    End Function

    Public Function GetPropertyNameB(Of TModel, TProperty)(ByVal [property] As Expression(Of Func(Of TModel, TProperty))) As String
        Dim memberExpression As MemberExpression = DirectCast([property].Body, MemberExpression)
        Return memberExpression.Member.Name
    End Function

End Class

Public Class miClase
    Private _dni As String
    Private _nombre As String

    Public Property DNI() As String
        Get
            Return _dni
        End Get
        Set(ByVal value As String)
            _dni = value
        End Set
    End Property

    Public Property Nombre() As String
        Get
            Return _nombre
        End Get
        Set(ByVal value As String)
            _nombre = value
        End Set
    End Property

End Class

El ejemplo es mío,  pero la solución no.

http://stackoverflow.com/questions/10606841/how-can-i-get-a-property-name-for-a-type-without-the-need-to-instantiate-an-obje

http://www.codeproject.com/Questions/253756/Linq-Get-Property-Name-using-VB-Net

Vale en próxima versiones lo tendremos más fácil por lo menos en C# 6.0
https://roslyn.codeplex.com/discussions/552376