我有一个Map表,使用GEOGRAPHY
类型存储位置。由于Entity Framework Core不支持空间类型,我必须在我的应用程序中使用MapView
和Lat
列映射Long
视图。然后,当使用Lat
触发器插入或更新到视图中时,我将这些Long
和geography::Point
值转换为INSTEAD OF
。
例:
CREATE TRIGGER [dbo].[MapViewInsertInstead] ON [dbo].[MapView]
INSTEAD OF INSERT
AS
IF ((SELECT Lat FROM inserted) IS NOT NULL AND (SELECT Long FROM inserted) IS NOT NULL)
BEGIN
INSERT INTO [dbo].[Map] (HouseId, HousePoint)
SELECT HouseId
geography::Point(Lat, Long, 4326)
FROM inserted
END
这已经工作了一段时间,但我一直在插入一行。我现在正在进行包含地图数据的数据的批量导入任务。一次在View中插入多行时,如下所示:
INSERT INTO MapView (HouseId, Lat, Long)
VALUES(0x1, 10, 10), (0x2, 10, 10);
我收到此错误:
子查询返回的值超过1。当子查询跟随=,!=,<,<=,>,> =或子查询用作表达式时,不允许这样做。
因此,只有在一次插入一个Map行时,此触发器才有效。我可以在触发器内部修改以允许插入多行吗?
这是因为这句话:
(SELECT Lat FROM inserted) IS NOT NULL
期望一个值与条件进行比较。
你可以做的是通过删除IF
语句来重写逻辑,而是将检查包含在INSERT
语句本身中:
CREATE TRIGGER [dbo].[MapViewInsertInstead] ON [dbo].[MapView]
INSTEAD OF INSERT
AS
BEGIN
INSERT INTO [dbo].[Map] (HouseId, HousePoint)
SELECT HouseId
geography::Point(Lat, Long, 4326)
FROM inserted
WHERE Lat IS NOT NULL
AND Long IS NOT NULL
END
您可能不希望无效的INSERT以静默方式失败。所以只要跳过空检查,如果有人试图插入NULL,geography::Point
函数将引发错误。例如
CREATE OR ALTER TRIGGER [dbo].[MapViewInsertInstead] ON [dbo].[MapView]
INSTEAD OF INSERT
AS
BEGIN
set nocount on;
INSERT INTO [dbo].[Map] (HouseId, HousePoint)
SELECT HouseId, geography::Point(Lat, Long, 4326)
FROM inserted;
END