¿Las interfaces fluidas son más flexibles que los atributos y por qué?

15

En un tutorial de EF 4.1 Code First se proporciona el siguiente código:

public class Department
{
    public int DepartmentId { get; set; }
    [Required]
    public string Name { get; set; }
    public virtual ICollection<Collaborator> Collaborators { get; set; }
}

Luego se explica que la interfaz fluida es más flexible:

Las anotaciones de datos son definitivamente fáciles de usar, pero es preferible utilizar un enfoque programático que brinde mucha más flexibilidad.

Luego se da el ejemplo de uso de la interfaz fluida:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Department>().Property(dp => dp.Name).IsRequired();
    modelBuilder.Entity<Manager>().HasKey(ma => ma.ManagerCode);
    modelBuilder.Entity<Manager>().Property(ma => ma.Name)
        .IsConcurrencyToken(true)
        .IsVariableLength()
        .HasMaxLength(20);
}

No puedo entender por qué la interfaz fluida es supuestamente mejor. ¿Es realmente? Desde mi perspectiva, parece que las anotaciones de datos son más claras y tienen una sensación semántica más clara.

Mi pregunta es ¿por qué una interfaz fluida sería una mejor opción que usar atributos, especialmente en este caso?

(Nota: soy bastante nuevo en todo el concepto de interfaces fluidas, así que no espere ningún conocimiento previo sobre esto).

Referencia: http://codefirst.codeplex.com/

Tjaart
fuente
Esta pregunta no se trata realmente de interfaces fluidas. La diferencia está entre usar atributos y código normal. Si el código no fuera fluido, no cambiaría mucho su pregunta.
svick
Las interfaces fluidas de @svick son básicamente códigos normales, pero lo expresan de una manera diferente. Nos alejamos de especificar cosas en código plano a atributos, ahora con interfaces fluidas parece que algunos están retrocediendo y avanzando hacia la especificación de cosas en código nuevamente. Solo quiero entender por qué usarías código en lugar de atributos. ¿Las interfaces fluidas justifican alejarse de los atributos y volver a codificar todo nuevamente?
Tjaart

Respuestas:

13

Las anotaciones de datos son estáticas, por ejemplo, esta declaración de método no puede cambiar en tiempo de ejecución:

  [MinLength(5)]
  [MaxLength(20,ErrorMessage="Le nom ne peut pas avoir plus de 20 caractères")]
  public new string Name { get; set; }

La interfaz fluida puede ser dinámica:

   if (longNamesEnabled)
   {
      modelBuilder.Entity<Manager>().Property(ma => ma.Name)
        .HasMaxLength(100);
   }
   else
   {
      modelBuilder.Entity<Manager>().Property(ma => ma.Name)
        .HasMaxLength(20);
   }

sin mencionar que el código se puede reutilizar entre propiedades.

Garrett Hall
fuente
2
¿Por qué crees que la longitud (o cualquier otra propiedad) de la misma propiedad cambiaría en tiempo de ejecución?
Yusubov
1
@ElYusubov: Comenzaría con los escenarios en los que no conocía la longitud del campo en el momento de la codificación.
Wyatt Barnett
@WyattBarnett: puede tener sentido tener la longitud del campo como variable solo cuando los parámetros de dominio se obtienen dinámicamente de algún servicio o fuente externa no tipada. Sin embargo, tratar dinámicamente las propiedades del dominio requeriría un enfoque de codificación defensivo.
Yusubov
1
@ElYusubov, podría tener dos propiedades que deben ser exactamente iguales, excepto por la longitud, por lo que las paso a una función que las configura dinámicamente. Es por eso que el autor los llamó más flexibles.
Garrett Hall
1
@ElYusubov, puede hacer que la longitud del campo sea una configuración en la configuración del proyecto, que se alimenta a app.config o web.config. Luego, si la longitud de un campo de base de datos cambió, puede cambiar la longitud en el archivo .config sin recompilar y volver a implementar la aplicación.
Kyralessa
8

No creo que esa declaración deba aplicarse ampliamente; Es muy específico de Code First. En Code First, las anotaciones de datos incluyen solo un subconjunto de la funcionalidad que está disponible en la API fluida. En otras palabras, hay ciertas configuraciones de modelo que solo se pueden hacer usando la API fluida.

Por ejemplo, estas son algunas de las cosas que no se pueden especificar utilizando las anotaciones:

  • La precisión de una propiedad DateTime
  • La precisión y la escala de las propiedades numéricas.
  • Una propiedad de cadena o binaria como longitud fija
  • Una propiedad de cadena como no unicode
  • El comportamiento al borrar de las relaciones
  • Estrategias de mapeo avanzadas

Personalmente, tiendo a usar las anotaciones de datos relacionadas con la validación siempre que sea posible, ya que otras tecnologías como MVC también pueden aprovecharlas. Para todo lo demás, prefiero la API fluida.

bricelam
fuente
¿Puedes dar un ejemplo de lo que solo se puede hacer con la API fluida? También sería interesante saber por qué han elegido hacerlo de esta manera. Estoy tratando de entender APIs flexibles frente a métodos más convencionales y el marco de la entidad es solo un ejemplo. Quiero saber por qué lo preferirían sobre los atributos. Para mí, los atributos parecen más correctos y legibles.
Tjaart
1
@Tjaart He agregado algunos ejemplos. Al diseñar esto, hubo dos principios motivadores principales. Primero, permita que los desarrolladores elijan. Algunas personas ven los atributos como una violación de POCO, a otros les gusta su naturaleza declarativa. En segundo lugar, aproveche los atributos existentes y solo introduzca otros nuevos para escenarios comunes. Probablemente estarás de acuerdo en que los ejemplos que di arriba son relativamente poco comunes.
bricelam
Noté que el comportamiento de OnDelete solo parece estar disponible en la API fluida. ¿Puedes pensar por qué decidieron hacerlo de esta manera? Esto es realmente a lo que estoy tratando de llegar con esta pregunta. La violación de POCO puede ser una buena razón si está compartiendo las clases entre proyectos. ¡Puede terminar agregando una dependencia de marco de entidad que no desea si usa atributos!
Tjaart
@Tjaart, no recuerdo las razones exactas. Me uní al equipo hacia el final de la función Code First y no estuve aquí por su diseño. Sin embargo, veré si puedo conseguir que alguien más del equipo pese.
bricelam
1

La respuesta a su pregunta se proporciona en el enlace.

Luego, define las restricciones aplicables a su dominio dentro de este método mediante programación.

Básicamente, es más o menos preferible usar Atributos versus enfoque programático, donde el enfoque programático tiene más control sobre la entidad. Sin embargo, existe una forma personalizada de agregar atributos para decorar su modelo que también puede verse.

Al utilizar este enfoque, incluso puede describir las relaciones entre tablas y columnas. En pocas palabras, si está dispuesto a tener más control de grano fino sobre su dominio, puede usar este nuevo enfoque que viene con EF4.1.

Sin embargo, para escenarios comunes de validación, la aplicación de Atributos debería funcionar bien porque es robusta para cubrir la mayoría de los casos; Además, puede ahorrarle tiempo.

Yusubov
fuente
¿Puedes ilustrar cómo la forma programática te da más control? Realmente no lo entiendo en este momento.
Tjaart
Por ejemplo, tome este ".IsConcurrencyToken (verdadero)": ¿cómo haría esto en una definición de atributo?
Yusubov
[ConcurrencyCheck] <- que en realidad parece más simple
Tjaart
buena captura, ¿cómo describirías las "relaciones entre tablas y columnas"?
Yusubov
[ForeignKey ("PersonId")] <- así, lo que probablemente no sea tan sencillo como .HasForeignKey (t => t.ProjectId), aunque todo lo que se necesita es dejar que ForeignKey () tome una lambda al igual que la interfaz fluida. Todavía no explica por qué uno es mejor que el otro.
Tjaart
0

Mi opinión es que recomiendan la API fluida para las implementaciones de código primero porque usted describe explícitamente cómo se crean las relaciones en la base de datos. Si usa anotaciones de datos, la base de datos creada por Entity Framework puede no ser lo que espera. Su ejemplo inicial es muy simple, así que, como usted, simplemente usaría el método de anotación de datos.

str8killinit
fuente
¿Puede dar un ejemplo de que la base de datos no es lo que espera y cómo una interfaz fluida evita que esto suceda?
Tjaart