9

如何使该列与数据库中的 PERSISTED COMPUTED 列相似?

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

    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 {}
        }
}
4

3 回答 3

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,它应该正确添加计算列。

进一步说明update-database -targetMigration: [name of migration to go back to]:如果您弄错了公式,那么您将不得不通过执行然后再执行另一个并在那里修改您的公式来恢复迁移,add-migration name并以更新数据库结束。可能有更好的方法,但这是我发现和使用的。

但是,我还没有找到使该领域持续存在的方法。

于 2013-01-22T11:02:50.287 回答
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)");
    }
}
于 2017-08-04T08:39:05.893 回答
0

我使用接受的答案中提出的方法遇到了一些麻烦。我提供了一个对我有用的替代解决方案。

运行此查询时遇到错误:

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

错误信息:

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

正如我们所见,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

- 编辑 -

我发现了为什么会出现投射错误;它与迁移无关,与我的代码有关。我在创建时没有正确转换计算列:

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

这样做的正确语法是这样的:

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

因此,我已恢复Ignore()调用并将所有内容切换回接受的答案中提出的方法。

JotaBe 致敬以寻求帮助。

于 2018-05-03T10:13:33.970 回答