使用 EF Core 创建视图
Create View using EF Core
按照此 blog post 中的指导,我添加了一个 ef 核心 (dotnet 6) 迁移,我将 t-sql 粘贴到其中以创建视图。
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql(@"
exec('create view [dbo].[vwSpotlightExtract] as
with
exceptions as (
select id from dbo.Application
where CTaxNumber in (
select
app.CTaxNumber
from dbo.Application app
group by app.CTaxNumber
having count(*) > 1
)
union
-- duplicate bank account
select id from dbo.Application where concat(BankSortCode, ':', BankAccountNumber) in (
select concat(app.BankSortCode, ':', app.BankAccountNumber)
from dbo.Application app
where app.BankAccountNumber is not null
group by concat(app.BankSortCode, ':', app.BankAccountNumber)
having count(*) > 1
)
union
-- duplicate uprn
select id from dbo.Application where uprn in (
select app.uprn from dbo.Application app
group by app.uprn having count(*)>1
)
),
LastAppStatus as (
select app.Id, app.UTRN,
max(rh.Id) LastRebateHistoryID
from dbo.Application app
inner join dbo.RebateHistory rh on app.ID = rh.ApplicationId
where rh.ApplicationId is not null --and rh.ApplicationId not in (select ID from exceptions)
and app.RequestType = 0 -- BACS
and ISNULL(app.PaymentStopped, 0) = 0 -- Payment NOT Stopped
--and app.id not in (select id from exceptions) -- to prevent sending stuff to spotlight
group by app.Id, app.UTRN
)
select
app.UTRN [Application Number],
'Personal' [Personal or Business Bank Account? (required)], -- always Personal
REPLACE(app.BankSortCode, '-', '') [Sort code (required)],
app.BankAccountNumber [Account number (required)],
NULL [Business name (required if business)],
app.AccountPayerFirstName [First Name (required if personal)],
app.AccountPayerSurname [Surname (required if personal)],
CASE WHEN LEN(CONCAT(addr.SAO_Start_No, addr.SAO_Start_Sfx)) > 0 and LEN (CONCAT(addr.SAO_End_No, addr.SAO_End_Sfx)) > 0 then CONCAT(addr.SAO_Start_No, addr.SAO_Start_Sfx, '-', addr.SAO_End_No, addr.SAO_End_Sfx)
WHEN LEN(CONCAT(addr.SAO_Start_No, addr.SAO_Start_Sfx)) > 0 and LEN (CONCAT(addr.SAO_End_No, addr.SAO_End_Sfx)) = 0 then CONCAT(addr.SAO_Start_No, addr.SAO_Start_Sfx)
WHEN LEN(CONCAT(addr.SAO_Start_No, addr.SAO_Start_Sfx)) = 0 and LEN (CONCAT(addr.SAO_End_No, addr.SAO_End_Sfx)) > 0 then CONCAT(addr.SAO_End_No, addr.SAO_End_Sfx)
else NULL end as
[Flat number (optional)], -- secondary addressable number or name
case when LEN(addr.PAO_Desc) > 0 then addr.PAO_Desc
when LEN(addr.SAO_Desc) < 0 then addr.SAO_Desc
ELSE NULL
end as [Building name (optional)],-- primary addressable name
CASE WHEN LEN(CONCAT(addr.PAO_Start_No, addr.PAO_Start_Sfx)) > 0 and LEN (CONCAT(addr.PAO_End_No, addr.PAO_End_Sfx)) > 0 then CONCAT(addr.PAO_Start_No, addr.PAO_Start_Sfx, '-', addr.PAO_End_No, addr.PAO_End_Sfx)
WHEN LEN(CONCAT(addr.PAO_Start_No, addr.PAO_Start_Sfx)) > 0 and LEN (CONCAT(addr.PAO_End_No, addr.PAO_End_Sfx)) = 0 then CONCAT(addr.PAO_Start_No, addr.PAO_Start_Sfx)
WHEN LEN(CONCAT(addr.PAO_Start_No, addr.PAO_Start_Sfx)) = 0 and LEN (CONCAT(addr.PAO_End_No, addr.PAO_End_Sfx)) > 0 then CONCAT(addr.PAO_End_No, addr.PAO_End_Sfx)
end [Building number (optional)],
addr.Street_Name [Street name (required)],
addr.Postcode [Address postcode (required)],
case when app.AccountType = 0 then 'Single'
when app.AccountType = 1 then 'Joint'
end as [Single or Joint account type (if personal)], -- new field coming
convert(varchar, app.AccountPayerDOB, 103) [Date of birth (if personal)],
NULL [Limited or non-limited (if business)],
NULL [Company registration number (if business)]
, ec.EventName
, app.ID
from dbo.Application app
left outer join dbo.AcademyNonDDPayers nondd on app.CTaxNumber = nondd.CTaxNumber
inner join dbo.CTaxAddress addr on RIGHT('000000000000'+ISNULL(app.uprn,''),12) = addr.uprn and nondd.CTaxPropertyRef = addr.CTaxPropertyRef
inner join LastAppStatus las on app.ID = las.ID
inner join dbo.RebateHistory rh on las.LastRebateHistoryID = rh.ID
inner join dbo.EventCode ec on rh.EventCodeId = ec.ID
where ec.ID = 11')
");
}
这会导致发布管道出现故障。如果我从部署工件中获取 sql 脚本的内容并粘贴到 SSMS 中,则会看到以下错误:
我不确定这是为什么,因为创建视图语句似乎正确地包含了开始和结束语句:
CREATE VIEW
不能在IF
/BEGIN
逻辑里面;它必须是批处理中唯一的语句。典型的解决方法是创建如下脚本:
IF OBJECT_ID(N'dbo.viewname', N'V') IS NULL
BEGIN
EXEC sys.sp_executesql N'CREATE VIEW dbo.viewname AS SELECT 1;';
END
GO
ALTER VIEW dbo.viewname
AS
... real view code ...
在较新版本的 SQL 服务器中,您可以这样做:
CREATE OR ALTER VIEW dbo.viewname
AS
... real view code ...
但这仍然必须存在于自己的批次中。这意味着它不能在 IF/BEGIN
内,除非您对整个视图 使用动态 SQL 。例如:
IF (some condition)
BEGIN
EXEC sys.sp_executesql N'CREATE VIEW dbo.viewname
AS
... all that view code ...;';
END
您是否能够从 EF 核心生成任何这些表单,我只是不知道。有时我们希望 ORM 可以做所有事情,但通常它只能做一个非常小的子集。
无论如何,我不确定您要达到的逻辑。 (如果某行在某些 table 中不存在,请创建一个视图?那只会起作用一次。)
按照此 blog post 中的指导,我添加了一个 ef 核心 (dotnet 6) 迁移,我将 t-sql 粘贴到其中以创建视图。
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql(@"
exec('create view [dbo].[vwSpotlightExtract] as
with
exceptions as (
select id from dbo.Application
where CTaxNumber in (
select
app.CTaxNumber
from dbo.Application app
group by app.CTaxNumber
having count(*) > 1
)
union
-- duplicate bank account
select id from dbo.Application where concat(BankSortCode, ':', BankAccountNumber) in (
select concat(app.BankSortCode, ':', app.BankAccountNumber)
from dbo.Application app
where app.BankAccountNumber is not null
group by concat(app.BankSortCode, ':', app.BankAccountNumber)
having count(*) > 1
)
union
-- duplicate uprn
select id from dbo.Application where uprn in (
select app.uprn from dbo.Application app
group by app.uprn having count(*)>1
)
),
LastAppStatus as (
select app.Id, app.UTRN,
max(rh.Id) LastRebateHistoryID
from dbo.Application app
inner join dbo.RebateHistory rh on app.ID = rh.ApplicationId
where rh.ApplicationId is not null --and rh.ApplicationId not in (select ID from exceptions)
and app.RequestType = 0 -- BACS
and ISNULL(app.PaymentStopped, 0) = 0 -- Payment NOT Stopped
--and app.id not in (select id from exceptions) -- to prevent sending stuff to spotlight
group by app.Id, app.UTRN
)
select
app.UTRN [Application Number],
'Personal' [Personal or Business Bank Account? (required)], -- always Personal
REPLACE(app.BankSortCode, '-', '') [Sort code (required)],
app.BankAccountNumber [Account number (required)],
NULL [Business name (required if business)],
app.AccountPayerFirstName [First Name (required if personal)],
app.AccountPayerSurname [Surname (required if personal)],
CASE WHEN LEN(CONCAT(addr.SAO_Start_No, addr.SAO_Start_Sfx)) > 0 and LEN (CONCAT(addr.SAO_End_No, addr.SAO_End_Sfx)) > 0 then CONCAT(addr.SAO_Start_No, addr.SAO_Start_Sfx, '-', addr.SAO_End_No, addr.SAO_End_Sfx)
WHEN LEN(CONCAT(addr.SAO_Start_No, addr.SAO_Start_Sfx)) > 0 and LEN (CONCAT(addr.SAO_End_No, addr.SAO_End_Sfx)) = 0 then CONCAT(addr.SAO_Start_No, addr.SAO_Start_Sfx)
WHEN LEN(CONCAT(addr.SAO_Start_No, addr.SAO_Start_Sfx)) = 0 and LEN (CONCAT(addr.SAO_End_No, addr.SAO_End_Sfx)) > 0 then CONCAT(addr.SAO_End_No, addr.SAO_End_Sfx)
else NULL end as
[Flat number (optional)], -- secondary addressable number or name
case when LEN(addr.PAO_Desc) > 0 then addr.PAO_Desc
when LEN(addr.SAO_Desc) < 0 then addr.SAO_Desc
ELSE NULL
end as [Building name (optional)],-- primary addressable name
CASE WHEN LEN(CONCAT(addr.PAO_Start_No, addr.PAO_Start_Sfx)) > 0 and LEN (CONCAT(addr.PAO_End_No, addr.PAO_End_Sfx)) > 0 then CONCAT(addr.PAO_Start_No, addr.PAO_Start_Sfx, '-', addr.PAO_End_No, addr.PAO_End_Sfx)
WHEN LEN(CONCAT(addr.PAO_Start_No, addr.PAO_Start_Sfx)) > 0 and LEN (CONCAT(addr.PAO_End_No, addr.PAO_End_Sfx)) = 0 then CONCAT(addr.PAO_Start_No, addr.PAO_Start_Sfx)
WHEN LEN(CONCAT(addr.PAO_Start_No, addr.PAO_Start_Sfx)) = 0 and LEN (CONCAT(addr.PAO_End_No, addr.PAO_End_Sfx)) > 0 then CONCAT(addr.PAO_End_No, addr.PAO_End_Sfx)
end [Building number (optional)],
addr.Street_Name [Street name (required)],
addr.Postcode [Address postcode (required)],
case when app.AccountType = 0 then 'Single'
when app.AccountType = 1 then 'Joint'
end as [Single or Joint account type (if personal)], -- new field coming
convert(varchar, app.AccountPayerDOB, 103) [Date of birth (if personal)],
NULL [Limited or non-limited (if business)],
NULL [Company registration number (if business)]
, ec.EventName
, app.ID
from dbo.Application app
left outer join dbo.AcademyNonDDPayers nondd on app.CTaxNumber = nondd.CTaxNumber
inner join dbo.CTaxAddress addr on RIGHT('000000000000'+ISNULL(app.uprn,''),12) = addr.uprn and nondd.CTaxPropertyRef = addr.CTaxPropertyRef
inner join LastAppStatus las on app.ID = las.ID
inner join dbo.RebateHistory rh on las.LastRebateHistoryID = rh.ID
inner join dbo.EventCode ec on rh.EventCodeId = ec.ID
where ec.ID = 11')
");
}
这会导致发布管道出现故障。如果我从部署工件中获取 sql 脚本的内容并粘贴到 SSMS 中,则会看到以下错误:
我不确定这是为什么,因为创建视图语句似乎正确地包含了开始和结束语句:
CREATE VIEW
不能在IF
/BEGIN
逻辑里面;它必须是批处理中唯一的语句。典型的解决方法是创建如下脚本:
IF OBJECT_ID(N'dbo.viewname', N'V') IS NULL
BEGIN
EXEC sys.sp_executesql N'CREATE VIEW dbo.viewname AS SELECT 1;';
END
GO
ALTER VIEW dbo.viewname
AS
... real view code ...
在较新版本的 SQL 服务器中,您可以这样做:
CREATE OR ALTER VIEW dbo.viewname
AS
... real view code ...
但这仍然必须存在于自己的批次中。这意味着它不能在 IF/BEGIN
内,除非您对整个视图 使用动态 SQL 。例如:
IF (some condition)
BEGIN
EXEC sys.sp_executesql N'CREATE VIEW dbo.viewname
AS
... all that view code ...;';
END
您是否能够从 EF 核心生成任何这些表单,我只是不知道。有时我们希望 ORM 可以做所有事情,但通常它只能做一个非常小的子集。
无论如何,我不确定您要达到的逻辑。 (如果某行在某些 table 中不存在,请创建一个视图?那只会起作用一次。)