EF Core逆向工程PostgreSQL视图时列非空性未保留问题求助
EF Core数据库优先模式下PostgreSQL视图逆向工程丢失非空性的问题与解决
问题场景
SQL Server环境下的正常表现
在SQL Server中使用EF Core数据库优先模式,通过dotnet-ef CLI逆向工程表和视图时,视图列的非空性可以被正确保留。
例如以下SQL Server架构:
CREATE TABLE [dbo].[Terminal] ( [Id] int NOT NULL IDENTITY, [Tid] nvarchar(max) NOT NULL, [ActivedAt] datetime2 NULL, CONSTRAINT [PK_Terminal] PRIMARY KEY ([Id]) ); CREATE OR ALTER VIEW [dbo].[TerminalView] WITH SCHEMABINDING AS SELECT [t].[Id], [t].[Tid], ISNULL(CAST(IIF([t].[ActivedAt] IS NULL, 0, 1) AS BIT), 0) AS [IsActive] FROM [dbo].[Terminal] AS [t];
逆向工程后生成的TerminalView实体类正确保留了非空性:
public partial class TerminalView { public int Id { get; set; } public string Tid { get; set; } = null!; public bool IsActive { get; set; } }
PostgreSQL环境下的异常表现
迁移到PostgreSQL后,使用相同逻辑创建表和视图:
CREATE TABLE IF NOT EXISTS public.terminal ( id integer NOT NULL GENERATED BY DEFAULT AS IDENTITY ( INCREMENT 1 MINVALUE 1 MAXVALUE 2147483647 CACHE 1 ), tid text COLLATE pg_catalog."default" NOT NULL, actived_at timestamp with time zone, CONSTRAINT "PK_terminal" PRIMARY KEY (id) ) CREATE OR REPLACE VIEW public.terminal_view WITH ( check_option=cascaded ) AS SELECT id, tid, actived_at IS NOT NULL AS is_active FROM terminal;
此时执行逆向工程,生成的TerminalView实体类所有属性都变为可空,丢失了原有的非空性:
public partial class TerminalView { public int? Id { get; set; } public string? Tid { get; set; } public bool? IsActive { get; set; } }
解决方案
方法1:修改PostgreSQL视图定义,显式声明非空约束
PostgreSQL视图不会自动继承基表列的非空属性,需要在视图的列定义中显式添加NOT NULL约束,让EF Core脚手架工具能识别到非空性。修改后的视图定义如下:
CREATE OR REPLACE VIEW public.terminal_view WITH (check_option=cascaded) AS SELECT id::integer NOT NULL, tid::text NOT NULL, (actived_at IS NOT NULL)::boolean NOT NULL AS is_active FROM terminal;
修改完成后重新执行dotnet ef dbcontext scaffold命令,生成的实体类会正确保留非空性。
方法2:手动修正逆向生成的代码
如果无法修改数据库视图,可以在逆向工程完成后手动调整代码:
- 修改
TerminalView实体类,移除属性的可空标记:
public partial class TerminalView { public int Id { get; set; } public string Tid { get; set; } = null!; public bool IsActive { get; set; } }
- 在
DbContext的OnModelCreating方法中,为视图的属性添加非空配置:
modelBuilder.Entity<TerminalView>(entity => { entity.HasNoKey().ToView("terminal_view"); entity.Property(e => e.Id).IsRequired(); entity.Property(e => e.Tid).IsRequired(); entity.Property(e => e.IsActive).IsRequired(); });
方法3:自定义EF Core脚手架逻辑(批量场景适用)
如果需要批量处理大量视图的非空性问题,可以自定义IScaffoldingModelFactory或者利用EF Core的脚手架扩展点,在逆向过程中自动识别视图列的非空规则。这种方式需要编写自定义代码,适合有大量视图需要处理的场景。
内容的提问来源于stack exchange,提问作者Nguyễn Kỳ Dương Trường
相关产品推荐
相关产品推荐

