EntityFramework 拒绝忘记旧专栏

EntityFramework refuses to forget old columns

我正在使用 EntityFramework 6.1.3,数据库优先。我现在希望我选择了代码优先...

我有一个包含一些 table 的数据库。我以前 用这些 table 构建了我的 edmx。然后我更改了几个列的类型并添加了几个列。例如,将 bit 列更改为 int 列。

我尝试使用 right-click -> Update Model from Database.

从数据库更新我的模型

似乎无论我做什么,EF 只会获取我创建 edmx 时数据库的状态。我尝试过的事情:

  1. 重新开放Visual Studio
  2. 重建项目
  3. 删除并重新添加实体(这是大多数人认为应该有效的方法)
  4. 在关闭 visual studio 时在整个项目中搜索 xml 或 C# 中的文本引用到我的专栏并替换它们。 (这似乎一开始有效,但如果我再次尝试从数据库更新,它会覆盖它们)
  5. 正在重新启动 SQL 服务
  6. 正在重启机器
  7. "Run Custom Tool" 在所有 .tt 文件上(应该不会有什么区别,但管他呢)

当我右键单击我的实体并 select "Table Mapping" 时,它始终总是在左侧显示旧的 bit 列。

这是我的数据库 table 设计:

可能值得注意的是,该实体正在离开视图,而不是直接离开 table。但是在我调查这个问题时,该视图实际上是 table 的 select *,并且我已经通过 powershell 确认视图返回的类型是一个 int:

PS> $conn = new-object data.sqlclient.SqlConnection("data source=localhost;initial catalog=dbname;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework")
PS> $conn.open()
PS> $query = $conn.createcommand()
PS> $query.commandtext = "select * from [dbname].[LocalCustom].[viewname]"
PS> $reader = $query.executereader()
PS> $reader.getschematable().rows[19]

ColumnName                      : ActiveMember
ColumnOrdinal                   : 19
ColumnSize                      : 4
NumericPrecision                : 10
NumericScale                    : 255
IsUnique                        : False
IsKey                           :
BaseServerName                  :
BaseCatalogName                 :
BaseColumnName                  : ActiveMember
BaseSchemaName                  :
BaseTableName                   :
DataType                        : System.Int32
AllowDBNull                     : False
ProviderType                    : 8
IsAliased                       :
IsExpression                    :
IsIdentity                      : False
IsAutoIncrement                 : False
IsRowVersion                    : False
IsHidden                        :
IsLong                          : False
IsReadOnly                      : False
ProviderSpecificDataType        : System.Data.SqlTypes.SqlInt32
DataTypeName                    : int
XmlSchemaCollectionDatabase     :
XmlSchemaCollectionOwningSchema :
XmlSchemaCollectionName         :
UdtAssemblyQualifiedName        :
NonVersionedProviderType        : 8
IsColumnSet                     : False

我现在的主要问题是... EF 如何知道它曾经是 bit 类型?它在哪里存储这些数据?? 当然我也想知道如何使用 UI 正确更新模型而不必删除和重新添加实体或我要去的其他任何东西必须做才能让它更新。

我对 EF 很失望:(

嗯,只是 edit/update 你的观点,即使没有任何变化。 EF 不会更新未修改的项目。

只要您没有 changed/updated 视图而是基础 table(s),EF 就无法检测到需要更改任何内容。我相信这种行为是为了防止每次都完全重建模型。


由于OP希望理解"why",我做了一些测试。

首先,我在上面创建了一个 table 和一个 "SELECT *" 视图:

create table TableToChange(rowKey bigint IDENTITY(1,1) not null, myBitFlag bit null, myIntFlag int)
go
create view SelectStarOnChangingTable as SELECT * FROM TableToChange
go

然后我对使用 :

创建的 sys 对象和列做了一些检查
select * 
from sys.all_objects AO 
    join sys.all_columns AC on AC.object_id=AO.object_id
where AO.object_id in (--insert your objet_ids here--)

对 table 对象做一些小改动:

alter table TableToChange
drop column myBitFlag
go
alter table TableToChange
add myBitFlag int
go

如果您再次 运行 架构查询,您会注意到更新后的列在 USER_TABLE 行和 VIEW 行中的类型不同(56 对 104)

改变 SelectStarOnChangingTable 视图而不做任何更改将强制 SQL 服务器更新。

我们现在有一个罪魁祸首:SQL服务器存储视图的列类型阻止 EF 更新其模型,即使实体是从头开始重建的。

这是我在使用Entity Framework 数据库优先时经常遇到的情况。当您对数据库进行一些更改以更新 EF 时,您应该:

  1. 删除.edmx
  2. 中修改的table
  3. 通过 right-click -> Update Model from Database -> check that table
  4. 将 table 重新添加到您的 .edmx