我们在SQLite数据库中定义了一个自引用关系......
Create Table Categories{
Id INTEGER PRIMARY KEY,
Name TEXT NOT NULL CHECK(length(Text) > 0),
ParentId INTEGER References Categories(Id),
IsSelected BOOL
};
我们正尝试在IsSelected字段上设置触发器,以自动在层次结构中传播值。
将值设置为True时,很容易。我们只需设置触发器将其父级设置为True,然后对其父级执行相同操作,向上移动层次结构直到它到达根目录。
但是,当我们将其设置为False时,该逻辑不适用,因为可能有另一个兄弟记录被更改仍然是真的,因此其父级仍然是真的。
那么如何在触发器中执行以下操作?注意,这显然是SQL,C#和LINQ的荒谬混合体,但它说明了我试图做的事情。
CREATE TRIGGER T_Categories_IsSelectedChanged
UPDATE OF IsSelected ON Categories
BEGIN
if(new.IsSelected)
Update Categories Set IsSelected = True Where Id = old.ParentId;
else
{
void isSiblingSelected = Categories
.Where(c => c.ParentId = old.ParentId)
.Any(c => c.IsSelected);
UPDATE Categories
SET IsSelected = isSiblingSelected
WHERE Id = old.ParentId;
}
END
现在技术上已经是'其他'条款适用于这两种情况。 If更像是一个短路,但也许我可以做这样的事情......
Update Categories
SET IsSelected = (
SELECT EXISTS(SELECT 1 FROM Categories
WHERE IsSelected = True
AND ParentId = old.ParentId
LIMIT 1))
Where ID = old.ParentId;
......但这只是一个猜测。我是在正确的轨道上吗?
答案 0 :(得分:0)
您可以参考http://www.sqlite.org/lang_expr.html#case。
我不确定,但你的代码可能就像,
CREATE TRIGGER T_Categories_IsSelectedChanged
UPDATE OF IsSelected ON Categories
BEGIN
case when new.isSelected then
Update Categories Set IsSelected = True Where Id = old.ParentId;
else
Update Categories Set IsSelected = Categories
.Where(c => c.ParentId = old.ParentId)
.Any(c => c.IsSelected);
END
答案 1 :(得分:0)
CASE不是声明;你只能在表达式中使用它。
但是,触发器具有WHEN clause,它采用任意SQL表达式:
CREATE TRIGGER T_Categories_IsSelectedChanged_true
AFTER UPDATE OF IsSelected ON Categories
FOR EACH ROW
WHEN new.IsSelected
BEGIN
UPDATE Categories
SET IsSelected = 1
WHERE Id = old.ParentId;
END;
CREATE TRIGGER T_Categories_IsSelectedChanged_false
AFTER UPDATE OF IsSelected ON Categories
FOR EACH ROW
WHEN NOT new.IsSelected
BEGIN
UPDATE Categories
SET IsSelected = (SELECT IFNULL(MAX(IsSelected), 0)
FROM Categories
WHERE ParentId = old.ParentId)
WHERE Id = old.ParentId;
END;