该ixset
库(或ixset-typed
,更类型安全的版本)将帮助您解决此问题。它是支持 的关系部分的库,acid-state
它还处理数据的版本化序列化和/或并发保证,以防万一。
Happstack Book 有一个IxSet 教程。
关键ixset
是它会自动为您的数据条目管理“密钥”。
对于您的示例,可以为您的数据类型创建一对多的关系,如下所示:
data User =
User
{ name :: String
, birthDate :: Date
} deriving (Ord, Typeable)
data Message =
Message
{ user :: User
, timestamp :: Date
, content :: String
} deriving (Ord, Typeable)
instance Indexable Message where
empty = ixSet [ ixGen (Proxy :: Proxy User) ]
然后,您可以找到特定用户的消息。如果你已经建立了IxSet
这样的:
user1 = User "John Doe" undefined
user2 = User "John Smith" undefined
messageSet =
foldr insert empty
[ Message user1 undefined "bla"
, Message user2 undefined "blu"
]
...然后您可以通过以下方式查找消息user1
:
user1Messages = toList $ messageSet @= user1
如果您需要查找消息的用户,只需像平常一样使用该user
功能即可。这模拟了一对多的关系。
现在,对于多对多关系,情况如下:
data User =
User
{ name :: String
, birthDate :: Date
, messages :: [Message]
} deriving (Ord, Typeable)
data Message =
Message
{ users :: [User]
, timestamp :: Date
, content :: String
} deriving (Ord, Typeable)
...您创建一个索引ixFun
,它可以与索引列表一起使用。像这样:
instance Indexable Message where
empty = ixSet [ ixFun users ]
instance Indexable User where
empty = ixSet [ ixFun messages ]
要查找用户的所有消息,您仍然使用相同的功能:
user1Messages = toList $ messageSet @= user1
此外,如果您有用户索引:
userSet =
foldr insert empty
[ User "John Doe" undefined [ messageFoo, messageBar ]
, User "John Smith" undefined [ messageBar ]
]
...您可以找到所有用户的消息:
messageFooUsers = toList $ userSet @= messageFoo
如果您不想在添加新用户/消息时更新消息的用户或用户的消息,则应该创建一个中间数据类型来模拟用户和消息之间的关系,就像在 SQL 中一样(并删除users
andmessages
字段):
data UserMessage = UserMessage { umUser :: User, umMessage :: Message }
instance Indexable UserMessage where
empty = ixSet [ ixGen (Proxy :: Proxy User), ixGen (Proxy :: Proxy Message) ]
然后,创建一组这些关系将使您可以通过消息和消息查询用户,而无需更新任何内容。
考虑到它的作用,该库有一个非常简单的界面!
编辑:关于您的“需要比较的昂贵数据”:ixset
仅比较您在索引中指定的字段(因此要在第一个示例中查找用户的所有消息,它会比较“整个用户”)。
Ord
您可以通过更改实例来控制它比较索引字段的哪些部分。因此,如果比较用户对您来说成本很高,您可以添加一个userId
字段并修改instance Ord User
为仅比较此字段。
这也可以用来解决先有鸡还是先有蛋的问题:如果你有一个 id,但既没有 aUser
也没有 aMessage
怎么办?
然后,您可以简单地为该 id 创建一个显式索引,通过该 id (with userSet @= (12423 :: Id)
) 找到用户,然后进行搜索。