24

Las tablas de datos fuertemente tipadas admiten tipos de campo "anulables", excepto que el diseñador no le permitirá cambiar la configuración a "permitir valores nulos" para ningún campo de tipo de valor. (es decir: los tipos de cadenas permiten los valores nulos, pero los int no).Tipos anulables en datatables/datasets fuertemente tipados: ¿soluciones temporales?

La solución consiste en llamar a IsMyFieldNull() en cualquier momento que desee obtener Myfield. Si accede a MyField cuando contiene un nulo, arroja un eception.

Este es un gran dolor de cabeza, además de causar muchos errores de tiempo de ejecución cuando un nulo que aparece puede hacer que su aplicación se cuelgue. Me he quejado con Microsoft por años sobre esto, sin embargo, cada versión nueva de Visual Studio todavía no permite el uso de tipos de valores que aceptan valores de nulos.

Mi pregunta: ¿Alguien sabe de un método (s) de extensión de lujo que podrían utilizarse para solucionar este inconveniente importante?

+0

Puede modificar la definición de propiedades de fila en el archivo .Designer del DataSet para la tabla, pero parece que se vuelve a crear cada vez que se modifica el DataSet a través del diseñador de VS, incluso si no toca la tabla específica. –

Respuesta

2

En VS 2008 puede simplemente ingresar un '0' en la propiedad nullvalue.
Si está utilizando vs2005 debe hacerlo con un editor XML. Debe agregar msprop:nullValue="0" como atributo a la columna.

+4

El problema es que un "0" es un valor legítimo ... lo que realmente necesito (o quiero) es valor nulo = nulo, y el tipo de datos es int? en lugar de int. –

1

Acepto que sería una buena característica permitir tipos de nullable.

Si establece la propiedad "NullValue" en la columna a "-1" en lugar de "(Lanzar excepción)" la propiedad devolverá -1 cuando la columna es nula en lugar de arrojar una excepción. Aún debe configurar la columna para permitir nulos.

Alternativamente, siempre puede establecer el tipo de datos en "System.Object" y permitir nulls = true. Puede acceder al valor de la columna sin tener que utilizar el método "IsMyFieldNull()". El valor de la columna será "System.DbNull.Value" cuando la columna sea nula. Si no le gusta usar "System.DbNull.Value", puede establecer la propiedad "NullValue" en "(Nothing)" en lugar de "(Throw exception)" y luego comparar el objeto con una referencia nula.

+0

-1 es un valor válido en la base de datos, por lo que no puedo usar eso. Pero no olvides que también estoy hablando de todos los tipos de valores. DateTime, dobles, etc. –

+0

También podría, de forma estándar, usar el valor máximo del tipo de valor para representar nulo. Para un byte es 255 y para un int32 es 2,147,483,647 (int32.MaxValue). Tenga en cuenta que el valor máximo para un valor de fecha será diferente de lo que puede esperar de la base de datos. Date.MaxValue no es igual al SQL DateTime o SmallDateTime más grandes. En general, el valor máximo de un tipo de valor nunca se usa en la práctica, mientras que en el caso de un byte, el valor mínimo (0) se usa con frecuencia. –

+3

Carter, hay una serie de soluciones alternativas, ninguna de las cuales es aceptable en la edad de los tipos que aceptan valores. ;) –

-2

Se introdujeron tipos anulables en .net 3.0, estos se pueden usar con conjuntos de datos. Se declara una int anulable como esto int? myNullableInt = null Aquí hay un enlace al artículo de MSDN: Nullable Types C#

Personalmente, me gustaría dirigir claramente de los valores nulos en las bases de datos en el primer lugar (si usted tiene la luxry de hacer esto). NULL está realmente allí para permitir un estado "Indefinido" o "Desconocido". Es raro tener este problema, por ejemplo, un campo de cadena que contiene un apellido a menudo se configurará como nulo, mientras que el valor predeterminado para "" sería una opción mucho mejor. Poner nulos en las bases de datos hace que las cosas sean innecesariamente difíciles Null Values In Databases, adicionalmente propaga nulos en el código y usted tiene que trabajar para evitar excepciones de referencia nulas.

Desafortunadamente, hay muchas cosas malas escritas en Internet sobre los DB (como el uso excesivo de null como correcto). Estos puntos de vista son normalmente de personas que realmente no entienden la teoría detrás de ellos, otro ejemplo clásico es un DB sin relaciones "porque es más flexible/más rápido para manejar estos en código". Esto significa que el desarrollador debe volver a escribir la funcionalidad existente [capa de la base de datos] que la base de datos inevitable maneja de manera más eficiente y con una fiabilidad mucho mayor. Digo inevitabilidad ya que, por supuesto, el desarrollador que realiza la reescritura está implementando nuevamente cosas que Oracle/Microsoft/Quien ha tenido equipos grandes que pasan mucho tiempo optimizando etc. Sin embargo, de vez en cuando, ve a alguien abogando por esto como un diseño. Este tipo realmente entiende las bases de datos, DBDebunkings, pasó mucho tiempo intentando desacreditar una gran cantidad de argumentos sin sentido que quitan las bases de datos relacionales de sus raíces teóricas.

+8

No pedí un sermón sobre los males de los nulos. Lo escuché 1000 veces. Estoy buscando una manera fácil de hacer que los nullables funcionen con conjuntos de datos fuertemente tipados. Tal vez un método de extensión o similar. Y, los nulables se introdujeron en .net 2, no 3. –

+0

Qué rudo. OK, me salió mal la versión del framework, pero eso no importa, lo que dije sigue en pie. No soy exactamente un novato, he estado .netting desde la beta 1.0. Lástima que los sermones no tomaron. –

+5

Keith, no tratando de ser grosero, solo que respondiste una pregunta que no hice. –

-1

No estoy seguro de por qué var x = !IsMyFieldNull() ? MyField : null (o similar) es un dolor de cabeza.

supongo que se podría escribir una envoltura alrededor de SqlDataReader para atrapar esos valores nulos de alguna manera cuando se lee los datos en su DataTable, o se podría escribir el equivalente de .TryParse() para sus consultas: algo agradable y encapsuladas como:

var x = myDataTable.TryParse(myField); 

donde .TryParse es un método de extensión buscando algo como:

public static TryParse(DataRow myField) 
{ 
    if(!myField == DbNull) //Or similar 
     return myField.Value; 
} 

Esto es, como se puede ver, básicamente pseudo-código en bruto, pero se entiende la idea. Escribe tu código una vez, luego llámalo como un método de extensión.

+0

Allen, el problema es la verbosidad de un escenario del mundo real: var x = MyDataTable.IsMyfieldNull()? (Int?) Null: (int?) MyDataTable.MyField; Ahora repite eso 5 veces para 20 tablas con 20 columnas en cada tabla. No es divertido;) Ah, y no olvide el código necesario para la asignación también .. –

7

Si está utilizando .Net 3.5 o superior, puede haber estas extensiones podrían ser de utilidad para usted: http://msdn.microsoft.com/en-us/library/system.data.datarowextensions.field.aspx

Según la documentación, que es totalmente compatible con los tipos anulables. Se permite el uso de construcciones como

MyRow.Field<int?>("MyField") 

y si lo ha asignado ao desde una variable existente del tipo correcto, el compilador puede inferir el tipo de forma automática y se puede dejar de lado el especificador de tipo, por lo que es tan corto como

int? myVar = MyRow.Field("MyField"); 
MyRow.Field("MyField") = myVar; 

aún no es perfecto, pero mucho más legible que tener que utilizar IsMyFieldNull(), etc en todas partes.

Ah, y si quieres ser más en el lado seguro con respecto a los nombres de columna falta de ortografía, que puede utilizar cosas como

MyRow.Field(MyTable.MyFieldColumn) 

No se olvide de agregar una referencia a System.Data.DataSetExtensions.

+1

He estado usando esto, y me ayuda, pero no está fuertemente tipado. Estoy buscando tablas de datos fuertemente tipadas que permitan tipos de campos con nulos (para tipos de valores) –

+0

Estoy de acuerdo. También estoy de acuerdo en que sería muy bueno si incluían algo para él en una próxima versión de Visual Studio. Esto es lo más cerca que tengo de usar las herramientas actuales.Estuve investigando la creación de plantillas T4, pero parecía mucho trabajo para lo que valía (para mí). –

+0

sí, es difícil justificar la reconstrucción de todas las herramientas del generador de conjuntos de datos solo para agregar una característica. (sí, también lo he investigado;) –

0

Puede hacer esto: establezca AllowDbNull en verdadero, si no está configurado; DefaultValue permanece activo; NullValue permanece activado (Lanzar excepción). Luego, desde el código, cuando desee configurar anular una columna, puede usar el método integrado Set_Column_Null(). Mira mi ejemplo:

if (entry.PosX.HasValue) 
    newRow.PosX = entry.PosX.Value; 
else 
    newRow.SetPosXNull(); 
0

sólo tenía que encontrar una solución alternativa para esto. Necesitaba cambiar algún código antiguo para una página web, escrito para ASP.NET 2.0. La página usa Telerik RadMenu, un control de menú. Este componente requiere que los elementos raíz tengan valores adecuados DBNull (para parentID). Entonces, cuando compilé el código anterior, el componente RadMenu me dio muchos problemas. Primeras excepciones con respecto a Restricciones, entonces no entendía qué elementos eran elementos raíz y todo parecía horrible.

Pero lo resolví y esto es lo que funcionó para mí.

En la página Propiedades de la columna de ParentID en el diseñador adaptador de la tabla, he utilizado: - AllowDBNull: true - DefaultValue: -1 (-1 es un valor que no se produce normalmente para esa columna) LA NullValue -property se quedó en "Throw Exception" ya que era imposible cambiarlo.

Y en el código que usa los valores del adaptador de tabla, utilicé esta construcción (VB.código de red, no C#, como se marca esta pregunta):

Dim MenuBarTable As DAL.Page.MenuBarDataTable 'The Table Adapter 
MenuBarTable = PageObj.GetMenuBar() 'The generated Get function 
MenuBarTable.ParentIDColumn.AllowDBNull = True 

    For Each row As Page.MenuBarRow In MenuBarTable.Rows 
     If row.IsParentIDNull() Then 
      row.SetParentIDNull() 
     End If 
    Next 

El código generado para los adaptadores de mesa genera dos funciones para cada columna que debe permitir DBNULLs. Deben utilizarse cuando se trata de NULL, pero es una solución torpe de Microsoft. Lo que ocurre detrás de las escenas es que el adaptador de tabla emitirá DefaultValue de la columna en lugar de NULL desde Get-function. Llamo a eso un "NULO simulado" o un "NULO falso".

La función IsParentIDNull() realmente comprobará si la fila contiene este "falso NULL", p. el DefaultValue de la columna, y cuando lo hace, estoy insertando un DBNull apropiado usando la función SetParentIDNull().

Esta solución funciona para mí, pero no es muy elegante, ni es muy eficiente, pero podría ser de ayuda para otra persona, espero.

Cuestiones relacionadas