miércoles, 14 de enero de 2015

DataAnnotations Cheat Sheet

He buscado por todo lado un Cheat Sheet como este para tener todas las opciones a mano pero no pude encontrar nada. Asi que arme uno propio, espero que les sirva de ayuda:


DataAnnotations Cheat Sheet v1.0


Nombre: AssociationAttribute

Descripcion: Especifica que un miembro de la entidad representa una relación, como una relacion de llave foranea.
Uso: [Association(Name, OtherKey, ThisKey)]
Ejemplo:
[Table(Name = "Clientes")]
public partial class Cliente
{
    [Column(IsPrimaryKey = true)]
    public string ClienteID;
    // ...
    private EntitySet<Pedido> _Pedidos;
    [Association(Storage = "_Pedidos", OtherKey = "ClienteID")]
    public EntitySet<Pedido> Pedidos

    {
        get { return this._Pedidos; }
        set { this._Pedidos.Assign(value); }
    }
}

Nombre: BindableTypeAttribute
Descripcion: Especifica si es que un tipo es tipicamente usado para hacer un   binding.
Uso: [BindableType(IsBindable = bool)]
Ejemplo:
  [BindableType(IsBindable = false)]
  public enum EstadoDeEntidad
  {
    Detached = 1,
    SinCambios = 2,
    Adicionado = 4,
    Borrado = 8,
    Modificado= 16,
  }

Nombre: CompareAttribute
Descripcion: Provee un atributo que compara dos propiedades.
Uso: [Compare(OtraPropiedad)]
Ejemplo:
public class Visitante
{
    public string EmailAddress { get; set; }
    [Compare("EmailAddress", ErrorMessage="Las  direcciones de correo no igualan." )]
    public string ConfirmEmailAddress { get; set; }
}

Nombre: ConcurrencyCheckAttribute
Descripcion: Se usa para especificar que una propiedad/columna tiene un modo "fixed" de concurrencia en el modelo EDM. Un modo de concurrecncia "fixed" significa que esta propiedad es parte de la revision de concurre3ncia de la entidad durante operaciones de guardado y solo se plica a propiedades escalares.
Uso: [ConcurrencyCheckAttribute]
Ejemplo:
  public class  Book
    {
        public long BookId { get; set; }
        public virtual string Title { get; set; }
        public Author Author { get; set; }
        [ConcurrencyCheckAttribute]
        [TimestampAttribute]
        public byte[] TimeStamp { get; set; }
    }

Nombre: CreditCardAttribute
Descripcion: Especifica que el campo es un numero de tarjeta de credito.
Uso: [CreditCardAttribute]
Ejemplo:
public class Buyer
{
    public string Nombre { get; set; }
    [CreditCardAttribute]
    public string CardNumber { get; set; }
}

Nombre: CustomValidationAttribute
Descripcion: Especifica que se usara un metodo de validacion a la medida para validar un campo.
Uso: [CustomValidation(typeof(Field), "Eval_function")]
Ejemplo:
public class CategoryMetadata
   {
      [CustomValidation(typeof(Category), "TestCategoryName")]
      public object CategoryName { get; set; }
   }
 
public static ValidationResult TestCategoryName(string pNewName, ValidationContext pValidationContext)
   {
      if (Regex.IsMatch(pNewName, @"^\d")) // cannot start with a digit
         return new ValidationResult("Cannot start with a digit", new List<string> { "CategoryName" });
      return ValidationResult.Success;
   }

Nombre: DataTypeAttribute
Descripcion: Specifica el nombre de tipo adicional para asociar al campo de dato.
Uso: [DataType(DataType.*)]
Ejemplo:
public class DataTypeEntity
{
    [DataType(DataType.Date, ErrorMessage = "Ingresaruna fecha valida (ej: 2/14/2011)")]
    public DateTime SaleDate { get; set; }

    [DataType(DataType.EmailAddress)]
    public string EmailAddress { get; set; }
}

Nombre: DisplayAttribute
Descripcion: Provee un atributo general que permite especificar cadenas localizables para los tipos y miembros de una clase.
Uso: [Display(Name = "*")]
Ejemplo:
public class Vendedor
{
    [Required]
    [DisplayName("Nombre Completo :")]
    public string Nombre { get; set; }

    [Display(Name = "Direccion de Correo")]
    public string DireccionEmail { get; set; }
}

Nombre: DisplayColumnAttribute
Descripcion: Especifieca la columna que se muestra en la tabla como una columna de llave Foránea.
Uso: [DisplayColumn("Campo a usar como Llave Foranea, Campo a usar para ordenar, ascendente/descendente)]
Ejemplo:
[DisplayColumn("Ciudad", "CodigoPostal", false)]
public partial class Direccion
{

}

Nombre: DisplayFormatAttribute
Descripcion: Especifica como se mostraran y formatearan los campos de datos mediante ASP.NET Dynamic Data.
Uso: [DisplayFormat(DataFormatString="*")]
Ejemplo:
public class Venta
{
    // Mostrar el dcampo de tipo monedacon el formato $1,345.50.
    [DisplayFormat(DataFormatString="{0:C}")]
    public object CostoEstandar;
    [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:dd/MM/yyyy hh:mm}")]
    public DateTime MiFecha { get; set; }
}

Nombre: EditableAttribute
Descripcion: Indica si un campo es o no editable.
Uso: [Editable(AllowEdit=bool,AllowInitialValue=bool)]
Ejemplo:
public class Persona
{
[Editable(AllowEdit=false)]
 public object Nombre{ get; set; }
 }

Nombre: EmailAddressAttribute
Descripcion: Valida una direccion de correo electronico.
Uso: [EmailAddress]
Ejemplo:
public class empleado
{
public string Nombre{get; set;}
[EmailAddress]
public string Notificacion{get; set;}
}

Nombre: EnumDataTypeAttribute
Descripcion: Permite mapear una enumeracion del .NET Framework a un campo de datos.
Uso: [EnumDataType(typeof(Enum Type))]
Ejemplo:
public enum eNivReorden {
        cero= 0,
        cinco= 5,
        diez=10,
        quince=15,
        veinte=20,
        veinticinco=25,
        treinta=30
    }
 public class Product_MD {
            [EnumDataType(typeof(eNivReorden ))]
            public object NivelDeReorden { get; set; }
        }

Nombre: FileExtensionsAttribute
Descripcion: Valida extensiones de archivos.
Uso: [FileExtensions(Extensions="*")]
Ejemplo:
public class Cliente{
    [FileExtensions(Extensions = "csv,txt",ErrorMessage = "Debe escoger un archivo .csv")]
    public string ImportFile{ get; set; }
}

Nombre: FilterUIHintAttribute
Descripcion: Representa un atributo usado para especificar el comportamiento de filtrado de una columna.
Uso: [FilterUIHint("El nombre de el control a usar para filtrado.")]
Ejemplo:
MetadataType(typeof(Product_MD))]
public partial class Product {
    private class Product_MD {
        [FilterUIHint("MultiForeignKey")]
        public object Category { get; set; }
        [FilterUIHint("BooleanRadio")]
        public object Discontinued { get; set; }
    }
}

Nombre: KeyAttribute
Descripcion: Indica una o mas propiedades que Identifican a una entidad.
Uso: [Key]
Ejemplo:
public class Cliente{
    [Key]
    public int Id { get; set; }
    public string nombre { get; set; }
}

Nombre: MaxLengthAttribute
Descripción: Especifica la longitud máxima de array o cadena que se permite en una propiedad.
Uso: [MaxLength(Largo)]
Ejemplo:
public class Cliente
{
    public virtual string IdCliente { get; set; }
    [MaxLength(50, ErrorMessage="El nombre no puede ser mayor a 50 chars" )]
    public virtual string NombreDeCompania{ get; set; }
}

Nombre: MetadataTypeAttribute
Descripción: Especifica la clase metadata a asociar con la clase del Modelo de datos.Indica que esta clase tienen una Clase Metadata Asociada. tiene un paramtro Type para espcificar que tipo contiene la metadata de la clase
Uso: [MetadataType(typeof(MetaData))]
Ejemplo:
public class CRMTypeMetadata
{
    [ScaffoldColumn(false)]
    public int TypeID { get; set; }
 
    [StringLength(100)]
    public string Url { get; set; }
}
 
[MetadataType(typeof(CRMTypeMetadata))]
public partial class CRMType
{
}

Nombre: MinLengthAttribute
Descripcion: Especifica la longitud Minima de un array o cadena que esta permitido en la propiedad.
Uso: [MinLength(Length)]
Ejemplo:
public class Customer
{
    public virtual string CustomerID { get; set; }
    [MinLength(3, ErrorMessage="El nombre no puede ser tan corto." )]
    public virtual string CompanyName { get; set; }
}

Nombre: PhoneAttribute
Descripcion: Especifica que el campo de datos el un numero de teléfono que se adecua al formato usando expresiones regulares para números de teléfono.
Uso: [Phone]
Ejemplo:
public class Cliente
{
    public virtual string ClienteID { get; set; }
    [Phone]
    public virtual string Nro_Telefono{ get; set; }
}

Nombre: RangeAttribute
Descripcion: Especifica un rango numerico permitido pára el valor de la propiedad.
Uso: [Range(Double,Double)], [Range(Int32,Int32)], [Range(Type,String,String)]
Ejemplo:
public class Item
{
public int Id { get; set; }
[Range(10, 1000, ErrorMessage = "El valor de {0} debe estar entre {1} y {2}.")]
public Double Peso { get; set; };
}

Nombre: RegularExpressionAttribute
Descripcion: Especifica que un campo de datos debe cumplir con la expresion regular indicada.
Uso: [RegularExpression(@"Regular_Expresion")]
Ejemplo:
public class Customer
{
    [RegularExpression(@"[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}", ErrorMessage = "Por favor entre un correo correcto")]
     public string Email { get; set; }
 }

Nombre: RequiredAttribute
Descripcion: Especifica que un campo es requerido/obligatorio.
Uso: [Required()]
Ejemplo:
public class Customer
{
    [Required]
    public virtual string CustomerID { get; set; }
    public virtual string CompanyName { get; set; }
}

Nombre: ScaffoldColumnAttribute
Descripcion: Especifica si una clase o columna de datos utiliza scaffolding.
Uso: [ScaffoldColumn(true)]
Ejemplo:
public class ProductMetadata
{
    [ScaffoldColumn(true)]
    public object ProductID;
    [ScaffoldColumn(false)]
    public object ThumbnailPhotoFileName;
}

Nombre: ScaffoldTableAttribute
Descripcion: Especifica si una clase o tabla de datos utiliza scaffolding.
Uso: [ScaffoldTable(bool)]
Ejemplo:
[MetadataType (typeof(ErrorLogMetada))]
[ScaffoldTable(false)]
public partial class ErrorLog
{
 
}

public class ErrorLogMetada
{

}

Nombre: StringLengthAttribute
Descripcion: Especifica el mínimo y máximo de caracteres permitidos en un campo de datos.
Uso: [StringLength(int maximumLength)]
Ejemplo:
public class ProductMetadata
{
    [StringLength(4, ErrorMessage = "El nombre no puede exceder 4 caracteres.")]
    public object ThumbnailPhotoFileName;

}

Nombre: TimestampAttribute
Descripcion: Especifica el tipo de datos de la columna como el que controla la version de la fila.Tambien especifica que esta columna sea incluida en la clausula Where de los comandos Update y Delete enviados a la base de datos, para verificacion de concurrencia.
Uso: [Timestamp]
Ejemplo:
public class Persona
{
    public Int64 Id { get; set; }
    public string Nombre{ get; set; }
    [Timestamp]
    public Byte[] Timestamp { get; set; }
}

Nombre: UIHintAttribute
Descripcion: Especifica un template o control de usuario que se usa para mostrar un campo de datos.
Uso: [UIHint(string uiHint)]
Ejemplo:
public partial class ProductMetadata
{
    [UIHint("UnidDisponibles")]
    [Range(100, 10000,
    ErrorMessage = "Unidades disponibles debe estar entre {1} y {2}.")]
    public object UnidDisponibles;
}

Nombre: UrlAttribute
Descripcion: Provee validacion para un campo tipo URL.
Uso: [Url]
Ejemplo:
public class MiModelo
{
    [Url]
    public string ServerAddress {get; set;}
}

Cualquier contribución para mejorar estos ejemplos sera bien recibida.

Copiar filas en la misma tabla solo cambiando el Id (TSQL)

Vamos a analizar diferentes escenarios en los cuales necesitamos copiar/clonar filas de una tabla a esa misma tabla, Solo cambiando el valor de un campo, Que en este caso sera el campo Id, Usando Microsoft SQL Server.

Supongamos que tenemos el AntId (Id original Id de el que queremos copiar las filas, en este caso este Id puede estar en varias filas o solo en una) y el NuevoId ( El Id nuevo que queremos poner en las filas que vamos a copiar/clonar)

Caso 1 - conocemos el nombre de la tabla y de todos sus campos:

El primer caso es de una tabla de la cual sabemos de antemano su nombre y su estructura, así que podemos escribir una consulta como la siguiente:

DECLARE @OldId int
DECLARE @NuevoId int
SET @AntId =13456 -- ejem.
SET @NuevoId =45687 -- ejem.

INSERT INTO MiTabla(Id,ColumnaA,ColumnaB,ColumnaC)
SELECT @NuevoId ,ColumnaA,ColumnaB,ColumnaC
FROM MyTable WHERE Id=@AntId 


Caso 2 - Conocemos el nombre de la tabla pero no de los campos:

En este caso nos vemos forzados a usar una tabla temporal para poder actualizar el ID antes de copiar las filas sin conocer el resto de las columnas:

DECLARE @AntId int
DECLARE @NuevoId int
SET @AntId =13456 -- ejm.
SET @NuevoId =45687 -- ejm.

--Copiar la filas que queremos a la tabla temporal
SELECT INTO #Temp FROM MiTabla WHERE Id=@AntId 

--Actualizar el Id en la tabla temporal    
UPDATE #Temp SET Id = @NuevoId 

--Copiar las filas con el nuevo Id de vuelta a MiTabla
INSERT INTO MiTabla  SELECT * FROM #Temp

--Borrar la tabla temporal     
if object_id(N'tempdb..#Temp'N'U'is not null  DROP TABLE #Temp
     
     
Caso 3 - No conocemos ni el nombre de la tabla ni de los campos:

Este escenario nos obliga a usar querys dinámicos para poder armar nuestra consulta con el nombre de la tabla, Nuestro primer intento seria algo así (y va a FALLAR)

DECLARE @NombreDeTabla varchar(32)
DECLARE @AntId int
DECLARE @NuevoId int

SET @NombreDeTabla ='MiTabla' --ejm podria llegar como parametro
SET @AntId =13456 -- ejm.
SET @NuevoId =45687 -- ejm.

SET @v_SQL = 'SELECT * INTO #Temp FROM ' + @NombreDeTabla ' WHERE Id='+  CAST(@AntId as varchar
EXEC(@v_SQL)
    
SET @v_SQL = 'UPDATE #Temp SET Id = '+  CAST(@NuevoId as varchar
EXEC(@v_SQL)

SET @v_SQL = 'INSERT INTO ' + @NombreDeTabla ' SELECT * FROM #Temp'
EXEC(@v_SQL)

--Borrar la tabla temporal    
SET @v_SQL = 'if object_id(N''tempdb..#Temp'', N''U'') is not null  DROP TABLE #Temp'
EXEC(@v_SQL)

     
Falla con errores porque el comando Exec() tienen su propio Scope ( que egoísta!) así que la tabla temporal no esta disponible para las siguientes sentencias.

La solución es usar una tabla temporal Global "##"  así estará disponible en el  Scope de el resto de los comandos Exec. 
Esto crea otro posible problema en sistemas multiusuario, porque se puede dar el caso que dos usuarios usen el proceso al mismo tiempo, y como la tabla temporal estaría disponible para ambos se pueden obtener errores o datos incorrectos. Así que necesitamos adicionar algo para que el nombre de la tabla temporal sea único para nuestro proceso, en este caso usaremos el nuevo Id que queremos usar para diferenciar el nombre de la tabla de otros usuarios concurrentes, Aunque puedes usar tu propio (y mas robusto) generador de Ids para estos casos si lo deseas.

La solución final queda así:

DECLARE @NombreDeTabla varchar(32)
DECLARE @AntId int
DECLARE @NuevoId int

SET @NombreDeTabla ='MiTabla' --ejm.
SET @AntId =13456 -- ejm.
SET @NuevoId =45687 -- ejm.

DECLARE @v_SQL varchar(1024)

SET @v_SQL = 'SELECT * INTO ##Temp'CAST(@NuevoId as varchar) +' FROM ' + @NombreDeTabla + ' WHERE Id = '+  CAST(@AntId as varchar
EXEC(@v_SQL)
    
SET @v_SQL = 'UPDATE ##Temp'CAST(@NuevoId as varchar) +' SET Id = '+  CAST(@NuevoId as varchar
EXEC(@v_SQL)

SET @v_SQL = 'INSERT INTO ' + @NombreDeTabla + ' SELECT * FROM ##Temp'CAST(@NuevoId as varchar)
EXEC(@v_SQL)
     
SET @v_SQL = 'if object_id(N''tempdb..##Temp'CAST(@NuevoId as varchar) +''', N''U'') is not null  DROP TABLE ##Temp'CAST(@NuevoId as varchar)  
EXEC(@v_SQL)
GO


Si lo ponemos como un Procedimiento Almacenado:

CREATE PROCEDURE dbo.CopiarConNuevoId
(
  @NombreDeTabla varchar(32),
  @NuevoId int,
  @AntId int
)
AS
  SET NOCOUNT ON
BEGIN
DECLARE @v_SQL varchar(1024)

SET @v_SQL = 'SELECT * INTO ##Temp'CAST(@NuevoId as varchar) +' FROM ' + @NombreDeTabla + ' WHERE Id = '+  CAST(@AntId as varchar
EXEC(@v_SQL)
    
SET @v_SQL = 'UPDATE ##Temp'CAST(@NuevoId as varchar) +' SET Id = '+  CAST(@NuevoId as varchar
EXEC(@v_SQL)

SET @v_SQL = 'INSERT INTO ' + @NombreDeTabla + ' SELECT * FROM ##Temp'CAST(@NuevoId as varchar)
EXEC(@v_SQL)
     
SET @v_SQL = 'if object_id(N''tempdb..##Temp'CAST(@NuevoId as varchar) +''', N''U'') is not null  DROP TABLE ##Temp'CAST(@NuevoId as varchar)  
EXEC(@v_SQL)
     
END
GO

Y eso es todo, espero que les sea de ayuda en alguna ocasión.