ndb 验证交易中的实体唯一性 [英] ndb verify entity uniqueness in transaction

查看:32
本文介绍了ndb 验证交易中的实体唯一性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在尝试创建具有属性的实体,该属性应该是唯一的或 None 类似于:

I've been trying to create entities with a property which should be unique or None something similar to:

class Thing(ndb.Model):
  something = ndb.StringProperty()
  unique_value = ndb.StringProperty()

由于 ndb 无法指定属性应该是唯一的,因此我像这样手动执行此操作是很自然的:

Since ndb has no way to specify that a property should be unique it is only natural that I do this manually like this:

def validate_unique(the_thing):
  if the_thing.unique_value and Thing.query(Thing.unique_value == the_thing.unique_value).get():
      raise NotUniqueException 

这很有效,直到我想在用于创建/更新实体的 ndb 事务中执行此操作.喜欢:

This works like a charm until I want to do this in an ndb transaction which I use for creating/updating entities. Like:

@ndb.transactional
def create(the_thing):
  validate_unique(the_thing)
  the_thing.put() 

然而 ndb 似乎只允许祖先查询,问题是我的模型没有祖先/父.我可以执行以下操作来防止出现此错误:

However ndb seems to only allow ancestor queries, the problem is my model does not have an ancestor/parent. I could do the following to prevent this error from popping up:

@ndb.non_transactional
def validate_unique(the_thing):
  ...

这感觉有点不合时宜,将某事声明为事务,然后在事务之外完成一个(重要的)部分.我想知道这是要走的路还是有(更好的)替代方案.

This feels a bit out of place, declaring something to be a transaction and then having one (important) part being done outside of the transaction. I'd like to know if this is the way to go or if there is a (better) alternative.

还有一些解释为什么 ndb 只允许祖先查询会很好.

Also some explanation as to why ndb only allows ancestor queries would be nice.

推荐答案

由于您的唯一性检查涉及(全局)查询,这意味着它受数据存储的最终一致性,这意味着它不能作为查询使用可能检测不到新创建的实体.

Since your uniqueness check involves a (global) query it means it's subject to the datastore's eventual consistency, meaning it won't work as the query might not detect freshly created entities.

一种选择是切换到祖先查询,如果您的预期用途允许您使用此类数据架构(或其他一些强一致的方法) - 同一篇文章中的更多详细信息.

One option would be to switch to an ancestor query, if your expected usage allows you to use such data architecture, (or some other strongly consistent method) - more details in the same article.

另一种选择是使用额外的数据作为临时缓存,您可以在其中存储所有新创建的实体的列表一段时间"(给它们足够的时间在全局查询中可见),除了查询结果中的那些之外,您还需要检查 validate_unique().这将允许您在事务之外进行查询,并且只有在唯一性仍然可能的情况下才进入事务,但最终结果是在事务内部手动检查缓存(即在事务内部不进行查询).

Another option is to use an additional piece of data as a temporary cache, in which you'd store a list of all newly created entities for "a while" (giving them ample time to become visible in the global query) which you'd check in validate_unique() in addition to those from the query result. This would allow you to make the query outside the transaction and only enter the transaction if uniqueness is still possible, but the ultimate result is the manual check of the cache, inside the transaction (i.e. no query inside the transaction).

存在第三种选择(以一些额外的存储消耗作为价格),基于数据存储对具有相同父级(或根本没有父级)的特定实体模型的唯一实体 ID 的实施.你可以有一个这样的模型:

A 3rd option exists (with some extra storage consumption as the price), based on the datastore's enforcement of unique entity IDs for a certain entity model with the same parent (or no parent at all). You could have a model like this:

class Unique(ndb.Model):  # will use the unique values as specified entity IDs!
    something = ndb.BooleanProperty(default=False)

您会像这样使用它(该示例使用唯一父键,它允许将模型重新用于具有唯一值的多个属性,如果您不需要它,您可以完全删除父键):

which you'd use like this (the example uses a Unique parent key, which allows re-using the model for multiple properties with unique values, you can drop the parent altogether if you don't need it):

@ndb.transactional
def create(the_thing):
    if the_thing.unique_value:
        parent_key = get_unique_parent_key()
        exists = Unique.get_by_id(the_thing.unique_value, parent=parent_key)
        if exists:
            raise NotUniqueException
        Unique(id=the_thing.unique_value, parent=parent_key).put()
    the_thing.put()


def get_unique_parent_key():

    parent_id = 'the_thing_unique_value'
    parent_key = memcache.get(parent_id)
    if not parent_key:
        parent = Unique.get_by_id(parent_id)
        if not parent:
            parent = Unique(id=parent_id)
            parent.put()
        parent_key = parent.key
        memcache.set(parent_id, parent_key)
    return parent_key

这篇关于ndb 验证交易中的实体唯一性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆