lunes, 4 de noviembre de 2013

Serializar un objeto .net

Serializar un objeto


1. Objeto a xml


Private Function CrearXMLDesdeObj(ByVal objClase As MiClase) As XmlDocument
Dim oXmlDocument As XmlDocument = New XmlDocument()
Dim oXmlSerializer As XmlSerializer = New XmlSerializer(objClase.GetType())
Dim oStringBuilder As StringBuilder = New StringBuilder()
Dim oStringWriter As StringWriterWithEncoding = New StringWriterWithEncoding(oStringBuilder, Encoding.UTF8)
oXmlSerializer.Serialize(oStringWriter, objClase )
oXmlDocument.LoadXml(oStringBuilder.ToString())
Return oXmlDocument
End Function

2. Quitar elemento vacíos


Serializar si no se quieren cosas raras, es muy fácil. El problema es cuando por ejemplo no quieren que salga la etiqueta cuando el valor es null, y por supuesto no se quiere poner la propiedad nulable. Aqui una funcion que borra esos elmentos.

Cuando se pone IsNullable = true si el valor es null se serializa


Public Function EliminarNullElementsFromXML(ByVal oXmlDocument As XmlDocument) As XmlDocument
Dim oXmlDeclaration As XmlDeclaration = CType(oXmlDocument.FirstChild, XmlDeclaration)
Dim oXDocument As XDocument = XDocument.Parse(oXmlDocument.OuterXml)
Dim oXElements As IEnumerable(Of XElement) = oXDocument.Descendants()
Dim oXElementsDelete As List(Of XElement) = New List(Of XElement)
Dim elem_list As IEnumerable(Of XElement) = From elem In oXElements Select elem
For Each element As XElement In elem_list
If (element.IsEmpty) Then
oXElementsDelete.Add(element)
End If
Next
oXElementsDelete.Remove()
oXmlDocument.LoadXml(oXDocument.ToString(SaveOptions.DisableFormatting))
oXmlDocument.InsertBefore(oXmlDeclaration, oXmlDocument.FirstChild)
Return oXmlDocument
End Function


3. Serializar Bool que pueden ser null

[Serializable]
public class Foo
{
[XmlIgnore]
public bool? Bar { get; set; }

[XmlAttribute("Bar")]
[EditorBrowsable(EditorBrowsableState.Never)]
public string xmlBar
{
get { return Bar.ToString(); }
set
{
if (string.IsNullOrEmpty(value)) Bar = null;
else Bar = bool.Parse(value);
}
}
}

4. Quitar los elementos vacios.

La funcion CleanEmptyTags, quita los elementos vacios , si la propiedad es un string tendrias varios

Public Class UtilXml

Public Shared Function Serialize(ByVal objectToSerialize As Object) As String
Dim oXmlDocument As XmlDocument = New XmlDocument()
Dim oXmlSerializer As XmlSerializer = New XmlSerializer(objectToSerialize.GetType())
Dim oStringBuilder As StringBuilder = New StringBuilder()
Dim oStringWriter As StringWriterWithEncoding = New StringWriterWithEncoding(oStringBuilder, Encoding.UTF8)
oXmlSerializer.Serialize(oStringWriter, objectToSerialize)
Return (CleanEmptyTags(oStringWriter.GetStringBuilder().ToString()))
End Function


Private Shared Function CleanEmptyTags(ByVal xml As String) As String
Dim regex As RegularExpressions.Regex = New RegularExpressions.Regex("(\s)*<(\w)*(\s)*/>")
Return regex.Replace(xml, String.Empty)
Return xml
End Function
End Class

martes, 29 de octubre de 2013

Sql Server int / int = ?

Esto es parecido a otra entrada de la sum

Tenemos lo siguiente

declare @p1 as integer
declare @p2 as integer
set @p1 = 12
set @p2 =10000
print @p1/@p2
Salida = 0

declare @p1 as integer
declare @p2 as decimal(16,2)
set @p1 = 12
set @p2 =10000
print @p1/@p2

Salida = 0.00120000000000000

Alguno estará diciendo que es obvio, pero os puedo asegurar que no siempre lo es.

martes, 17 de septiembre de 2013

Google nos hizo vagos….


Ya nadie se preocupa de escribir bien en un campo de búsqueda, sabemos que google lo hara.


Es difícil explicar al cliente que no somos Google y que eso lleva más trabajo de lo que cree, por muy fácil que Google lo haga.

Bueno pongamos a ello, vamos a darle al cliente lo que quiere (bueno más o menos)
  1. Saber cómo funciona las búsquedas, algo más que "like "
  2. Realizar búsquedas de palabras fonéticamente similares Soundex ()
  3. freetext 
  4. Problemas del freetext
  5. Si no estamos hablando de algo sencillo como un directorio de personas, no descartes el Lucene lo hay en .net buen artículo en dotnetslackers.com en
Con esto podrías intentar luego hacer las búsquedas para usuarios "vagos" (todos).

domingo, 1 de septiembre de 2013

Sum() & Sql Server

Curioseando, esto pasa en SqlServer no sé si con otros pasa (puedo asegurar que con Informix no pasa)

Ejemplo
SELECT SUM(precio) FROM libros

Error ->Mens. 8115, Nivel 16, Estado 2, Línea 1
Error de desbordamiento aritmético al convertir expresión al tipo de datos int.


Explicación

sum(column1) throws "Arithmetic overflow error"
sum() adopts the data type of the column type, so cast the column within the sum expression:

Genial usa el tipo de la columna, que en mi caso era un int


Solución
SELECT SUM( cast ( precio as bigint) ) FROM libros


martes, 27 de agosto de 2013

ADODB.Recordset está cerrado después de llamar a un sp

La chorrada de hoy me ha llevado, más de 3horas.

Situación:
- Un procedimiento que funciona en el SQL Server Management, con parámetros de entrada y recordset de salida. El SP hacia un insert y retornaba un recordset (hacia más cosas, esto es para resumir :P)
- Código Vb6, cuando ejecutaba el código y quería ver el contenido del recordset, el VB6 me daba un error de “La operación no está permitida si el objeto está cerrado.”
- El SP se había ejecutado porque tenía un registro más.

Di por supuesto que el problema estaba en como hacia la llamada al SP desde Vb6 (el SP funcionaba bien, se había ejecutado). Después de hacer un poco de I (sin +D porque desarrollo cero) pregunte a expertos en VB6 mayores que yo y nada.

La solución fue:
Añadiren el SP SET NOCOUNT ON al comienzo del código y SET NOCOUNT OFF justo antes de devolver los resultados finales

Si el procedimiento envía varios mensajes al cliente, el resulset no los procesa adecuadamente y suele dar ese mensaje de error.

La solución gracias a:
http://microsoft.public.es.sqlserver.narkive.com/fNVcXJuO/modo-correcto-de-ejecutar-sp

Por si alguno le interesa:
Llamar con command

A mí me valía con

Dim cSql as String
Dim cSql = " execute miProceimiento ‘parametro1’, ‘parametro2’ "
Set rst = New ADODB.Recordset
rst.Open cSql, gConexion, adOpenForwardOnly, adLockReadOnly
If Not rst.EOF Then

End if

miércoles, 14 de agosto de 2013

Sql, curioseando

Unas utilidades para conocer la estructura de una base de datos de sqlserver ,

Obtener las bases de datos de un servidor

select name as descripcion
from sys.databases
WHERE name not like 'EXTRA%'

Obtener todas las tablas o vistas de un servidor

select name, object_id ,create_date from sys.tables order by name
select name , object_id ,create_date from sys.views order by name

Obtener todas las columnas de un todas las tablas o vistas de una bbdd

select t.object_id, c.name,system_type_id, max_length, c.precision , scale ,is_nullable, c.column_id from sys.columns c ,
sys.tables t where t.object_id= c.object_id
select t.object_id, c.name,system_type_id, max_length, c.precision , scale ,is_nullable,c.column_id from sys.columns c ,
sys.views t where t.object_id= c.object_id
order by t.OBJECT_ID, c.column_id

Obtener las columas que forman parte de todos los índices de una base de datos

select t.TABLE_NAME, COLUMN_NAME from INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE as c
inner join INFORMATION_SCHEMA.TABLE_CONSTRAINTS as t on
t.CONSTRAINT_NAME = c.CONSTRAINT_NAME
where t.CONSTRAINT_TYPE='PRIMARY KEY'
order by TABLE_NAME

Obtener los trigger de una bbdd

select t.object_id, name, e.type, e.type_desc, t.parent_id
from sys.triggers t, sys.trigger_events e
where t.type ='TR' and t.object_id=e.object_id

Obtener todos los SP , funciones de una bbdd

select name, object_id from sys.objects where type in ('FN' ,'P', 'TF', '[IF]') order by name
Obtener todos los parámetros de entrada de todos los sp de una base de datos
SELECT SPECIFIC_NAME, PARAMETER_NAME, data_type, CHARACTER_MAXIMUM_LENGTH , NUMERIC_PRECISION, NUMERIC_SCALE, max_length , is_nullable
FROM INFORMATION_SCHEMA.PARAMETERS, sys.types
WHERE PARAMETER_MODE='IN' and INFORMATION_SCHEMA.PARAMETERS.DATA_TYPE =sys.types.name
ORDER BY SPECIFIC_NAME, ORDINAL_POSITION

Buscar texto dentro de un procedimiento o función de sql

-- @texto -->texto a buscar
--@BBDD --> nombre de la base de datos, si no se pasa ninguno busca en todas las bases de datos del servidor
Create PROCEDURE [dbo].[Find_Text](@texto varchar(50), @BBDD varchar(75)= null) as
begin

declare @ssQL nvarchar(max)
declare @nombreBBDD varchar(75)
declare @sWhere varchar(max)
declare @texo_find varchar(75)
declare @index_Final int
declare @tablaSP table
(
name_SP varchar(500),
name_BBDD varchar(500),
Tipo varchar(10),
ID INT
)
declare @tablaBasesDatos table
(
nombreBBDD varchar(75)
)

INSERT INTO @tablaBasesDatos
select db.name from sys.databases db WHERE DB.name = ISNULL(@BBDD,DB.NAME) and DB.name not in('msdb','DatabaseControl','master','model','tempdb')
order by db.database_id

set @sWhere = 'where '
if CHARINDEX(',',@texto)=0
begin
set @sWhere = @sWhere+ ' sc.text like ''%'+@texto+'%'' '
end
else
begin
WHILE CHARINDEX(',',@texto,0) > 0
begin
Set @index_Final= CHARINDEX(',',@texto,0)+1
set @texo_find= substring(@texto,0, @index_Final)
set @texto= REPLACE(@texto,@texo_find,'')
set @sWhere = @sWhere+ ' sc.text like ''%'+ ltrim(rtrim(replace( @texo_find,',',''))) +'%'' OR '
end
if @texto<> ''
BEGIN
set @sWhere = @sWhere+ ' sc.text like ''%'+ ltrim(rtrim( @texto)) +'%'' '
END
end

WHILE EXISTS (SELECT * FROM @tablaBasesDatos)
BEGIN

SELECT top 1 @nombreBBDD = nombreBBDD FROM @tablaBasesDatos

set @ssQL='select DISTINCT so.name ,'''+@nombreBBDD+''', so.XTYPE, sc.ID
from ' + @nombreBBDD + '..sysobjects so inner join ' + @nombreBBDD + '..syscomments sc on so.id = sc.id AND sc.encrypted= 0 '+ @sWhere

BEGIN TRY
INSERT INTO @tablaSP
execute sp_executesql @ssQL
END TRY
BEGIN CATCH
END CATCH;
DELETE TOP (1) @tablaBasesDatos
END

SELECT name_SP,
CASE WHEN Tipo='FN' THEN 'F. ESCALAR'
WHEN Tipo='P' THEN 'PROCEDIMIENTO'
WHEN Tipo='TF' THEN 'F. TABLA' ELSE Tipo END as tipo
,name_BBDD , ID FROM @tablaSP order by name_BBDD,Tipo,name_SP

end

Ojo cuidado cuando se usa el syscomments !!!! Ejemplo de un "problemilla"

Creamos un procedimiento : nombre1 ( esto aparece en el syscomments sin problemas)
Cambiamos el nombre del procedimiento: pulsando sobre el nombre,boton derecho "Cambiar Nombre" y ponemos el nuevo nombre por "NEW _NOMBRE"
Ahora mira el syscomments !!! pues si en el syscomments en el texto del SP está el nombre viejo.
Está documentado http://support.microsoft.com/kb/243198
"Al cambiar el nombre de un procedimiento almacenado, una vista o un desencadenador no se actualiza la tabla SYSCOMMENTS"

domingo, 26 de mayo de 2013

Variables de SQL Server

Para controlar el anidamiento de SQL server podemos usar la variable
@@NESTLEVEL

MSDN
Ejemplo de uso, muy útil Ejemplo

domingo, 12 de mayo de 2013

The "GenerateResource" task failed unexpectedly.

Este ha sido un error, raro.
Una solución con dos proyectos: un proyecto de escritorio y una dll .net 2010 , Vb .net, framework 4

Cuando compilaba, algunas veces (no siempre) daba un error
The "GenerateResource" task failed unexpectedly

Para solucionarlo abría un par de formularios, limpiaba la solución y generaba y compilaba.

Esto es "pasable" si solo lo tengo que hacer una vez, pero no era mi caso. Buscando encontré una solución que me valía :

Modificar (con el bloc de notas) el fichero .vbproj y añadir
<generateresourceneverlocktypeassemblies>true</generateresourceneverlocktypeassemblies>

Ejemplo
<Code>
<project defaulttargets="Build" toolsversion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<propertygroup>
<generateresourceneverlocktypeassemblies>true</generateresourceneverlocktypeassemblies>
</propertygroup>
</code>

Un error similar con una explicación y solución diferente

martes, 16 de abril de 2013

Curiseando Dispose & Finalize

Hoy mirando el código de otro (lo juro ) tenía una cosa como está

Private Sub Button3_Click(sender As System.Object, e As System.EventArgs) Handles Button3.Click
Dim aux As MiClase
aux = funcion()
MessageBox.Show(aux.NewProperty)
MessageBox.Show(aux.OtraPropiedad)
End Sub

Public Function funcion() As MiClase
Dim oRet As MiClase = New MiClase()
Dim oRet2 As MiClase = oRet
Try
oRet.NewProperty = "otro valor"
Return oRet
Catch ex As Exception
Return Nothing
Finally
oRet.Dispose()
oRet = Nothing
End Try
End Function
Yo, que mi orígenes fueron el c y el c++ (no todo tiempo pasado fue mejor), siempre entiendo que el “dispose” libera todos objetos de la clase . Por supuesto sé que el Finally se ejecuta.

La pregunta de hoy es: qué valor tiene aux.NewProperty y aux.OtraPropiedad?.
Para dar alguna pista (o confundir más al lector) dejo la clase :
Public Class MiClase
Private newPropertyValue As String
Private _otraPropiedad As String

Public Property OtraPropiedad() As String
Get
Return _otraPropiedad
End Get
Set(ByVal value As String)
_otraPropiedad = value
End Set
End Property

Public Property NewProperty() As String
Get
Return newPropertyValue
End Get
Set(ByVal value As String)
newPropertyValue = value
End Set
End Property
Public Sub New()
newPropertyValue = "mi valor"
_otraPropiedad = "mi 2 valor"
End Sub

Public Sub Dispose()
_otraPropiedad = String.Empty
End Sub

End Class
La respuesta es: aux tiene valor. El return de la función ha retornado el puntero y la memoria realmente no se ha liberado. Dejo la captura del debug.

Ya puestos en la “funcion” he puesto un código que no “vale para nada”, solo para ver que realmente se usan punteros aunque no lo veamos
Dim oRet2 As MiClase = oRet
La pregunta es : ¿qué vale oRet2 después de ejecutar oRet = Nothing?. Le pasa exatamente lo mismo que al aux: todo son punteros


En C# funciona exactamente igual

miércoles, 3 de abril de 2013

IIF VB .net


Un programador C .net puede pensar que la instrucción iif de vb es equivalente al operador de compración ?
Una sorpresa: ¿que crees que saldrá en el MessageBox?
Dim total As Integer = 0
Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
Dim a As Integer = 1
Dim b As Integer = 2
Dim c As Boolean = IIf(a = b, funcion1("b"), funcion2("1"))
MessageBox.Show(total)
End Sub
Public Function funcion1(ByVal valor As String) As Boolean
total = total + 1
Return True
End Function
Public Function funcion2(ByVal valor As String) As Boolean
total = total + 1
Return True
End Function
2 Imagina que hicieras otra cosa:, consultas a base de datos, mostrar MessageBox , como ejecuta las dos funciones si una de ellas da Exception aunque nunca se cumpliera la condición para su llamada fallaría…

Y resulta que está documentado http://msdn.microsoft.com/es-es/library/27ydhh0d%28v=vs.80%29.aspx

“El IIF evalúa el código a ejecutar (tanto si la condición es verdadera o falsa) antes de ejecutarlo (esto no sé si es fallo de MS o es intencional). El problema que podemos encontrar con esto es que hay que asegurarse que las sentencias a ejecutar sean válidas en todas las condiciones, si no tendremos un excepción.”


Si tienes curiosidad C#, hace lo que esperas (o por lo menos lo que yo esero: el valor de total es 1
int total = 0;
private void button1_Click(object sender, EventArgs e)
{
int a = 1;
int b = 2;
bool c = (a == b ? funcion1("b") : funcion2("1"));
MessageBox.Show(total.ToString());
}
private bool funcion1(String valor)
{
total = total + 1;
return true;
}
private bool funcion2(String valor)
{
total = total + 1;
return true;
}

domingo, 31 de marzo de 2013

Indices base datos

El minuto de hoy: Tengo una consulta que tarda más de 3min. Ejecutando el plan de ejecución me dice que debería tener un índice más (hasta aquí todo normal).
Cuando veo el índice que me sugiere :
CREATE NONCLUSTERED INDEX [miindice]
ON [dbo].[mitabla] ([codigo],[nombre])
INCLUDE ([fecha], [cantidad])
Qué es esto??
Vaya hasta el momento (para mi) un índice era un conjunto de columnas. Resulta que ya no es así
existe el crear índices con columnas incluidas
MSDN
Por cierto con el índice la consulta mejoro en más de un 50% el tiempo

jueves, 21 de marzo de 2013

Servidores Vinculados SQLServer

Bueno últimamente nos ha tocado trabajar con servidores vinculados

Ambos servidores se ven:
En servidor1 está mibase1 donde esta mitabla1 con su columna nombredoc1 --> no es case-sensitive
En servidor2 está mibase2  donde esta mitabla2 con su columna nombredoc2 --> es case-sensitive

Si en servidor1 ejecuto
select top 1  NOMBREDOC2  from servidor2. mibase2 .dbo. mitabla2 --> ok
select top 1  nombredoc2  from servidor2. mibase2.dbo. mitabla2 --> ok
Si en servidor2 hago
select top 1  NOMBREDOC1  from servidor1. Mibase1 .dbo. mitabla1 -->  error
select top 1  nombredoc1  from servidor1. Mibase1.dbo. mitabla1--> ok

Lo ha configurado para que sea case-sensitive hasta el nombre de las columnas!!!!

La configuración es importante, pero si lo pones a nivel de estructura mira las implicaciones (sobre todo en una migración)

Pregunta es ¿Si se puede tener la BD definida como  case sensible y consultas NO?

Respuesta es :  hay que crear la BD como case no sensible y tablas columnas como sensibles


http://msdn.microsoft.com/en-us/library/ms143508(v=sql.105).aspx


SQL Server 2008 supports setting collations at the following levels:
•         Server
•         Database
•         Column
•         Expression


http://msdn.microsoft.com/en-us/library/ms187053(v=sql.90).aspx

Parameters for stored procedures or functions, alias data types, and variables are assigned the default collation of the database. To change the collation of an alias type, you must drop and re-create it.

Problemas de rendimiento


Servidor 2
select distinct a.fecha , a.nif ,
b.nombre  from basedatos2.dbo.tabla2 a ,servidor1.base1.dbo.tabla1 b
where a.nif = b.nif   and a.fecha = '08/10/2012' order by b.nombre asc --> 6sg
Servidor 1
select distinct a.fecha , a.nif ,
b.nombre  from servidor2.basedatos2.dbo.tabla2 a , base1.dbo.tabla1 b
where a.nif = b.nif  and a.fecha = '08/10/2012' order by b.nombre asc --> IMEDIATO
Para que vaya rápido en el servidor2
select distinct a.fecha , a.nif ,
b.nombre  from basedatos2.dbo.tabla2 a , openquery(servidor1, 'select * from base1.dbo.tabla1')  b
where a.nif = b.nif   and a.fecha = '08/10/2012' order by b.nombre asc -->INMEDIATO

Las soluciones posibles :
- mejorar las estructura de la consulta, (índices,  openquery)
- replicar la base de datos  Replicar las base de datos ( http://www.sqlservercentral.com/articles/Linked+Server/62246/)

La "chapu" para cuando vas fatal de tiempo  es aumentar el tiempo de time-out de las consultas de tu código

domingo, 10 de marzo de 2013

Informes, reports..


Lo reconozco odio hacer informes, me da igual el método

Hoy tenía 5min de descanso y he visto un link muy interesante
Generar archivos Excel como un señor con ClosedXml

Yo también lo reconozco en modo web también he cambiado el content-type

Para generar Word en el CodePlex Docx

Hace algunos años (más de 3) estos link me salvaron de un apuro
http://www.codeproject.com/KB/reporting-services/Reporting_ServicesByalifaraze.aspx

Para exportar a Word el report
http://www.codeproject.com/KB/reporting-services/report-viewer-hack.aspx

Localizador o multidioma en los report generados con el .net
http://www.codeproject.com/KB/aspnet/RDLC_Localization.aspx

Este link genial, uno se da cuenta lo que desconoce el office, lo reconozco es una locura, pero funciona.
Resumen: creas lo objetos, con ellos obtienes  el xsd para asociar al word. Hasta imágenes inserte en su día
http://www.codeproject.com/Articles/20287/Generating-Word-Reports-Documents
Más info
http://sophinet.wordpress.com/2011/03/10/open-xml/

Por si no lo sabes el Open Office no deja de ser un fichero comprimido. Apuesto que alguno no se lo cree…
Haz la prueba:
  1. Guarda un documento (me da igual Word o Excel, con la extensión .docx o .xlsx)
  2. Cambia la extensión por .zip
  3. Luego dar a ver que hay dentro.

viernes, 15 de febrero de 2013

VS & Nuget


NuGet es un add-in para Visual Studio 2010 y es un gestor de paquetes que permite instalar y configurar librerias y herramientas para utilizarlas dentro de nuestros proyecto

Información :
http://eduardosojo.com/2011/07/19/usuando-nuget-que-es-nuget/

http://docs.nuget.org/docs/start-here/using-the-package-manager-console

Cuando hay problemas que los tendremos

http://geeks.ms/blogs/fernandezja/archive/2012/05/22/vs2010-sp1-nuget-actualizaci-243-n-manual-de-nuget-copiando-y-pegando-archivos-cuando-tenemos-problemas-en-la-instalaci-243-n-actualizaci-243-n-en-vs2010-sp1.aspx

Muy útil para descargar el Sandcastle

La primera versión me instale el Sandcastle con el NutGet pero he querido hacer lo mismo en las máquinas de mis compañeros y fue imposible .. claro esto fue 3 años después

La buena noticia es que hay un msi
https://github.com/EWSoftware/SHFB/releases

1 el SandcastleHelpFileBuilder.msi
2 SHFBVisualStudioPackage.vsix

documentación : http://ewsoftware.github.io/SHFB/html/8c0c97d0-c968-4c15-9fe9-e8f3a443c50a.htm

Sinceramente, soy partidaria de hacer documentación, sobre todo para luego funcione el IntelliSense. Pero para que será útil, hay que hacerla según se hace el código. Pero si tu jefe quiere documentación para entregar esto es una buena solución


TFS - Team Foundation Sidekicks

Ahora trabajamos con TFS, en realidad y de momento únicamente lo usamos con control de código, antes usamos el Visual Source Safe (o VSS). Hay cosas que das por hechas, en el VSS nunca función bien a la hora de buscar quien tenía las cosas protegidas, pero con el paquete básico de TFS esa posibilidad ni siquiera la tienes ups!!!!. No queda más remedio que instalar una utilidad Team Foundation Sidekicks.. y problema resuelto Ok






viernes, 18 de enero de 2013

Super control de usuario

Los controles de usuario de Windows

Hoy ha pasado una cosa curiosa, un compi había creado una control de usuario que en el load hacia una consulta a la base de datos. Hasta aquí todo parece normal. Lo que ya no lo era tanto era si:
  1. Compilabas el proyecto
  2. En el Designer del formulario que lo contenía, en modo diseño se ejecutaba la consulta!!!
Por lo visto no es tan novedoso, aquí un ejemplo explicado lo mismo pero para el evento paint http://el-blog-de-thor.blogspot.com.es/2009/09/infectar-codigo-fuente.html

lunes, 14 de enero de 2013

DateTime.Parse & Marzo

Hoy hemos visto un error super curioso, leemos un fichero plano donde las fechas llegan con el formato dd-MMM-yy ( el formato no está decidió por nosotros)

Resulta que en una aplicación

fecha = DateTime.Parse("20-JAN-09") funciona
fecha = DateTime.Parse("20-MAR-09") falla No se puede reconocer la cadena como valor DateTime válido.

El problema parece ser en que no sabe si “MAR” es Marzo o Martes y da un error que no puede convertir la fecha, puesto que nuestro sistema operativo está en español la referencia cultural que está usando es “es”

Solución , usar DateTime.Parse con referencia cultural o DateTime.ParseExact (incluye el formato)

https://connect.microsoft.com/VisualStudio/feedback/details/729674/datetime-parse-fails-to-parse-correct-dates-or-accepts-incorrect-dates


Por si aun tienes curiosidad

Try
Dim fecha As DateTime
fecha = DateTime.Parse("20-JAN-09")
' falla ---> fecha = DateTime.Parse("20-MAR-09")
fecha = DateTime.ParseExact("20-MAR-09", "dd-MMM-yy", System.Globalization.CultureInfo.GetCultureInfo("en-US"), System.Globalization.DateTimeStyles.None)
fecha = DateTime.Parse("20-MAR-09", System.Globalization.CultureInfo.GetCultureInfo("en"), System.Globalization.DateTimeStyles.None)
fecha = DateTime.Parse("20-MAR-09", System.Globalization.CultureInfo.GetCultureInfo("en"))
fecha = DateTime.Parse("20-JAN-09", System.Globalization.CultureInfo.GetCultureInfo("es"))
' falla fecha = DateTime.Parse("20-MAR-09", System.Globalization.CultureInfo.GetCultureInfo("es"))
fecha = DateTime.ParseExact("20-MAR-09", "dd-MMM-yy", System.Globalization.CultureInfo.GetCultureInfo("es"), System.Globalization.DateTimeStyles.None)
fecha = DateTime.Parse("20-APR-09", System.Globalization.CultureInfo.GetCultureInfo("es"))
'falla --> fecha = DateTime.Parse("20-AVR.-09", System.Globalization.CultureInfo.GetCultureInfo("es"))
fecha = DateTime.Parse("20-APR-09", System.Globalization.CultureInfo.GetCultureInfo("fr"))
Catch ex As Exception

End Try

Me sorprendió que
fecha = DateTime.Parse("20-APR-09", System.Globalization.CultureInfo.GetCultureInfo("es"))

Funciona!!!!   El formato no es español, pero según la documentación

Este método intenta analizar s completamente para evitar que se produzca FormatException. Si es posible, omite los datos no reconocidos y rellena la información que falta acerca de mes, día y año con la hora actual. Si s contiene sólo una fecha y ninguna hora, este método supone que es medianoche (00:00). Se omiten los caracteres de espacio en blanco iniciales, centrales o finales que pueda haber en s. La fecha y la hora pueden ir entre corchetes con un par de caracteres NUMBER SIGN iniciales y finales ('#', U+0023) y pueden terminar con uno o más caracteres NULL (U+0000).”


Para evitar el FormatException, termina usando la InvariantCulture (que está en inglés) y por eso funciona

viernes, 11 de enero de 2013

sys.syscolumns o sys.columns parece lo mismo pero no lo es

Hoy he tenido un problema con   sys.syscolumns, la primera vez que lo vi pensaba que era sys.columns (parecido pero no es lo mismo)

La documentación del msdn deja mucho que desear para el sys.syscolumns
xtype - tinyint - Physical storage type from sys.types.
type - tinyint - Physical storage type from sys.types

Con esa explicación parece que debería tener el mismo valor , pero no es cierto en la columna type del sys.syscolumns hay valores como 0 o 39 que no están en el sys.types, en realidad esta en el sys.systypes (otra vez parece lo mismo pero no lo és)

Después de dar unas vueltas encontré las diferencias y cual tenia que usar

Catalog View es lo que se debería usar

En sys.syscolumns (Transact-SQL)
Tenia la siguiente nota :
"This SQL Server 2000 system table is included as a view for backward compatibility. We recommend that you use the current SQL Server system views instead. To find the equivalent system view or views, see Mapping SQL Server 2000 System Tables to SQL Server 2005 System Views. This feature will be removed in a future version of Microsoft SQL Server. Avoid using this feature in new development work, and plan to modify applications that currently use this feature."

MSDN equivalencias

Ejemplos para obtener información del catalogo

viernes, 4 de enero de 2013

Documentar si o si

Hoy hemos tenido una charla sobre el xml que se genera cuando compilamos, resulta que aun mucha gente no sabe que esto genera la documentación. Casi nunca documentamos, porque no vemos ningún fruto a los comentarios.

Para el que no sepa que es la documentación del código y para que vale, lee esto: MSDN

Depende de la versión del visual studio que tengas puede que tengas que instalar algún complemento para la documentación. La buena noticia es que las nuevas versiones del visual ya tiene la documentación para VB (antes solo estaba para C#)

Hasta el framework 3.5, prueba el NDoc, yo lo he usado y es fantástico. Super fácil de instalar y probar, con un montón de opciones para configurar.

También está disponible el Sandcastel (es válido para framework 4.0)
- Ayuda
- Instalarlo

Es útil, pero como todo si no lo has usado nunca vas a tardar un poco en verlo, para mi un pega es que es lento. Si no haces documentación empieza a escribirla según haces el código y prueba como sale la documentación para ver que sirve para algo y lo que puedes mejorar en tus comentarios.