如何在EF代码中首先创建持久计算列?

时间:2013-01-11 17:30:35

标签: sql-server entity-framework code-first ef-migrations

如何使此列与数据库中的PERSISTED COMPUTED列类似?

我当前的尝试(它在种子中加载所有带有null的CompCol行):

    public class Call
    {
        public Call()
        {
        }

        [Key]
        public int Id { get; set; }

        [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
        public string CompCol
        {
            get
            {
                return "ABC-" + Convert.ToString(Id).PadLeft(5, '0');
            }
            protected set {}
        }
}

3 个答案:

答案 0 :(得分:9)

我找到的解决方案是:

  1. 确保已关闭自动迁移。这样VS就会生成一个脚本(流畅的api代码)供我们进一步定制而不是仅仅运行它。所以在配置类中:

    public Configuration()
    {
        AutomaticMigrationsEnabled = false;
    }
    
  2. 将字段添加到类中并将其设置为计算如此,setter是私有的,因为我们显然无法写入计算字段:

    [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
    public string BreakdownNo { get; private set; }
    
  3. 然后在程序包管理器控制台中执行add-migration [xyz-name]以生成迁移代码,该代码将显示在具有给定名称的迁移文件夹下。

  4. 在迁移内注释Up()中的代码并添加自定义SQL,如下所示:

    public override void Up()
    {
        //AddColumn("dbo.Calls", "BreakdownNo", c => c.String());
        Sql("ALTER TABLE dbo.Calls ADD BreakdownNo AS ('BD'+RIGHT('00000'+ CAST(Id AS VARCHAR), 6))");
    }
    
  5. 在PM中执行update-database,它应该正确添加计算列。

  6. 进一步说明:如果您的公式错误,那么您必须通过执行update-database -targetMigration: [name of migration to go back to]然后再做add-migration name并在那里修改公式来恢复迁移,用update-database完成。可能有更好的方法,但这是我发现和使用的方式。

    但是我没有办法让这个领域保持不变。

答案 1 :(得分:1)

为什么不这样调用sql:

public class demo
{
    void demoMethod()
    {
        Model1 model = new Model1();//Model1 : DbContext
        model.Database.ExecuteSqlCommand("alter table Results drop column Total; alter table Results add Total AS (Arabic + English + Math + Science)");
    }
}

答案 2 :(得分:0)

我使用接受答案中提出的方法遇到了一些麻烦。我提供了另一种适合我的解决方案。

我在运行此查询时遇到了问题:

oDb.LogEntries.Where(Function(LogEntry) LogEntry.LogTime = dDate).SingleOrDefault

错误消息:

  

'LogEntry'上的'MinutesOffline'属性无法设置为'System.Int32'值。您必须将此属性设置为“System.Single”类型的非null值。

正如我们所看到的,EF 6.2正试图为该属性写一个值。这是否是由于EF内部尝试写入Private Set,我不知道。它几乎就像它。但最终的结果才是最重要的:声明失败了。

我没有将列设置为DatabaseGeneratedOption.Computed,而是完全忽略了它:Builder.Entity(Of LogEntry).Ignore(Function(LogEntry) LogEntry.MinutesOffline)

这使我能够创建一个只读属性:

Public ReadOnly Property MinutesOffline As Single
  Get
    Return IIf(Me.Scale < 1, 5, 0)
  End Get
End Property

它还有一个额外的好处,我们不必在生成的迁移中注释掉任何行。

我们仍然需要在Sql()中进行自定义Up()来电:

ALTER TABLE [LogEntries] ADD [MinutesOffline] AS (IIF([Scale] < 1, 5, 0)) PERSISTED

... PERSISTED关键字在此处有效。这将成为一个持久的计算列。

YMMV