流利的接口比属性更灵活吗?为什么?


15

在EF 4.1 Code First教程中,给出了以下代码:

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

然后说明了流畅的界面更加灵活:

数据批注绝对易于使用,但是最好使用编程方法来提供更大的灵活性。

然后给出使用流畅接口的示例:

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);
}

我不明白为什么据说流畅的界面会更好。真假的啊?从我的角度来看,数据注释看起来更加清晰,并且具有更清晰的语义感觉。

我的问题是,为什么流畅的界面会比使用属性更好的选择,尤其是在这种情况下?

(注意:我对流畅接口的整体概念还很陌生,所以请不要对此有所了解。)

参考:http : //codefirst.codeplex.com/


这个问题不是关于流畅的界面。使用属性和普通代码之间的区别。如果代码不流利,那么您的问题不会有太大变化。
svick 2012年

@svick流利的接口基本上是普通的代码,但是它以不同的方式表示。我们从用普通代码指定事物转移到属性,现在有了流畅的界面,似乎有些人正在回溯并再次朝着用代码指定事物迈进。我只想了解为什么您会使用代码而不是属性。流利的接口是否可以保证不再使用属性,而又可以再次对所有内容进行简单编码?
Tjaart

Answers:


13

数据注释是静态的,例如,此方法声明不能在运行时更改:

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

流利的界面可以是动态的:

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

更不用说代码可以在属性之间重用。


2
您为什么会认为同一属性的长度(或任何其他属性)在运行时会发生变化?
尤苏波夫

1
@ElYusubov:我将从在编码时不知道字段长度的情况开始。
Wyatt Barnett

@WyattBarnett:仅当从某些服务或外部非类型化源动态获取域参数时,才将字段长度作为变量才有意义。但是,动态处理域属性将需要防御性编码方法。
尤苏波夫

1
@ElYusubov您可以拥有两个属性,除了长度,它们必须完全相同,因此我将它们传递给一个动态设置它们的函数。这就是为什么作者称它们更灵活。
加勒特音乐厅

1
@ElYusubov,您可以在项目设置中将字段长度设置为设置,并将其输入到app.config或web.config中。然后,如果数据库字段长度更改,则可以更改.config文件中的长度,而无需重新编译和重新部署应用程序。
Kyralessa

8

我认为该声明不应广泛适用;它对于Code First非常特定。在Code First中,数据批注仅包含fluent API中可用功能的一部分。换句话说,某些模型配置只能使用Fluent API来完成。

例如,以下是一些无法使用注释指定的内容:

  • DateTime属性的精度
  • 数值属性的精度和小数位数
  • 固定长度的String或Binary属性
  • String属性为非unicode
  • 关系的删除行为
  • 先进的制图策略

就我个人而言,我倾向于尽可能使用与验证相关的数据注释,因为其他技术(例如MVC)也可以利用这些注释。对于其他所有方面,我更喜欢流畅的API。


您能否举一个只能使用流利的API进行操作的示例?知道为什么他们选择了这种方式也很有趣。我试图理解fleunt API与更传统的方法和实体框架只是一个例子。我想知道为什么他们喜欢它而不是属性。对我来说,属性似乎更正确和可读。
Tjaart

1
@Tjaart我添加了一些示例。在设计时,有两个主要的激励原则。首先,允许开发人员选择。有些人将属性视为违反POCO,其他人则将其视为声明性属性。其次,利用现有属性,仅在常见情况下引入新属性。您可能会同意,我在上面给出的示例相对少见。
bricelam 2012年

我确实注意到OnDelete行为似乎仅在流畅的API中可用。您能想到他们为什么选择这种方式吗?我确实想解决这个问题。如果您在项目之间共享类,则可能会违反POCO。如果使用属性,您可能最终会获得不需要的实体框架依赖项!
Tjaart

@Tjaart,我不记得确切的原因。我在Code First功能即将结束时加入了团队,但并不是因为它的设计。我会看看是否可以从团队中选拔其他人。
bricelam 2012年

1

链接中提供了您问题的答案。

然后,以编程方式在此方法中定义适用于您的域的约束。

基本上,相对于程序设计方法而言,或多或少地倾向于使用“属性”而非“程序设计方法”,因为程序设计方法对实体具有更多的控制权。但是,有一种添加属性以装饰模型的自定义方式,您可能也会看到它。

使用这种方法时,您甚至可以描述表和列之间的关系。底线是,如果您希望对您的域进行更细粒度的控制,则可以使用EF4.1随附的这种新方法。

但是,对于验证的常见情况,应用属性应该可以正常工作,因为它可以覆盖大多数情况。另外,它可以节省您的时间。


您能否说明编程方式如何为您提供更多控制权?我现在还不明白。
Tjaart

例如,使用此“ .IsConcurrencyToken(true)”-如何在属性定义上执行此操作?
尤苏波夫

[ConcurrencyCheck] <-实际上似乎更简单
Tjaart

很好,那么您将如何描述“表与列之间的关系”?
Yusubov

[ForeignKey(“ PersonId”)] <-像这样,它可能不如.HasForeignKey(t => t.ProjectId)那么简单,尽管所需要做的只是让ForeignKey()像流利的接口一样取一个lambda。它仍然没有解释为什么一个比另一个更好。
Tjaart

0

我的想法是,他们建议使用流利的API进行代码优先实现,因为您明确描述了如何在数据库中创建关系。如果使用数据批注,则可能不是由Entity Framework创建的数据库。您最初的示例非常简单,因此像您一样,我将只使用数据注释方法。


您能否举例说明数据库不是您所期望的,以及流畅的界面如何防止这种情况发生?
Tjaart
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.