如果父母不同,同一类型的两个实体是否可以拥有相同的ID? [英] Can a two Entities of the same Kind have the same ID if the parent is different?

查看:162
本文介绍了如果父母不同,同一类型的两个实体是否可以拥有相同的ID?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道数据存储会自动为根实体生成一个唯一的ID。但是,具有不同父母的同类实体呢?

数据存储库是否会自动为不同父母(相同种类)的同一种类的实体生成唯一ID?例如用户 - >邮。可以想象两个不同的用户每个都有一个具有相同ID的邮政吗?

解决方案

我为你写了一个JUnit测试。它使用lombok,但你也可以写出getter和setter。

  import com.google.appengine.tools.development .testing.LocalDatastoreServiceTestConfig; 
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
import com.googlecode.objectify。*;
import com.googlecode.objectify.annotation.Entity;
import com.googlecode.objectify.annotation.Id;
import com.googlecode.objectify.annotation.Parent;
import com.googlecode.objectify.util.Closeable;
导入junit.framework.Assert;
import lombok.Getter;
import lombok.Setter;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

import java.util.List;

public class IdAllocationTest {
@Entity
public static class ChildEntity {
@Parent
@Getter
@Setter
private价< ParentEntity>父母;
@Id
@Getter
@Setter
私人长ID;
}

@Entity
public static class ParentEntity {
@Id
@Getter
@Setter
private Long id;


public static class OfyService {
static {
try {
ObjectifyService.register(ChildEntity.class);
ObjectifyService.register(ParentEntity.class);
} catch(Exception e){
System.out.println(Could not initialized objectify service。+ e.toString());



public static Objectify ofy(){
return ObjectifyService.ofy();


public static ObjectifyFactory factory(){
return ObjectifyService.factory();



private static LocalServiceTestHelper helper = new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig());
private static Closeable objectifyBegin;

@BeforeClass
public static void beforeClass(){
helper.setUp();
objectifyBegin = ObjectifyService.begin();


@AfterClass
public static void afterClass(){
objectifyBegin.close();
helper.tearDown();
}

@Test
public void testIdAllocation(){
Ref< ParentEntity> parent1 = Ref.create(Key.create(ParentEntity.class,1L));
Ref< ParentEntity> parent2 = Ref.create(Key.create(ParentEntity.class,2L));

ChildEntity childEntity1 = new ChildEntity();
childEntity1.setParent(parent1);
childEntity1.setId(1L);

ChildEntity childEntity2 = new ChildEntity();
childEntity2.setParent(parent2);
childEntity2.setId(1L);

OfyService.ofy()。save()。entities(childEntity1,childEntity2).now();

列表< Key< ChildEntity>> keys = OfyService.ofy()。load().type(ChildEntity.class).keys()。list();
//如果发生覆盖,它将只是一个实体
Assert.assertEquals(keys.size(),2); (Key< ChildEntity> child:keys){

System.out.println(Key(+
Key('+ child.getParent())的
。 getKind()+',+ child.getParent()。getId()+),+
'+ child.getKind()+',+ child.getId()+ ));
}

while(true){
KeyRange< ChildEntity> keyRangeParent1 = OfyService.factory()。allocateIds(parent1,ChildEntity.class,100);
KeyRange< ChildEntity> keyRangeParent2 = OfyService.factory()。allocateIds(parent2,ChildEntity.class,100); (Key< ChildEntity> keyParent2:keyRangeParent2){
System.out.println(keyParent1.getId()+)的
$ b(Key< ChildEntity> keyParent1:keyRangeParent1){
,+ keyParent2.getId());
Assert.assertTrue(keyParent1.getId()!= keyParent2.getId());
}
}
}
}
}

在devserver上,这个单元测试的输出是这样开始的

  Key(Key('ParentEntity',1 ),'ChildEntity',1)
Key(Key('ParentEntity',2),'ChildEntity',1)
1,101
1,102
1,103
1,104
1,105

证明两件事: p>


  1. 具有不同祖先的相同Id是可能的

  2. devserver上的行为是id不会相互冲突(他们似乎使用相同的计数器)。基本上,这证明我们无法通过查看devserver来证明事物,但代码可以(理论上)在现场系统上运行。

警告:请不要部署此代码。这里有一个潜在的无限循环,实际命中的可能性非常小。必须大幅度增加分配的ID的数量并保留一个家长的分配ID以供比较。即使这样,在测试所有分配的ID之前,您仍然会遇到DeadlineExceeded和OutOfMemory异常。



摘要:
除非有人来自谷歌可以启发我们如何id分配的作品,没有太多我们可以找出。快速浏览数据存储实现显示分配是对数据存储的请求,因此没有可以进行深入分析的代码。

I我们只需要相信文档是正确的,何时它说


避免这种冲突的唯一方法是让您的应用程序通过DatastoreService.allocateIds()或AsyncDatastoreService.allocateIds()。
数据存储的自动ID生成器将跟踪已使用这些方法分配
的ID,并避免将它们重新用于
另一个实体,因此您可以安全地使用这些ID而不会发生冲突。


关于id分配方法。


I know that datastore will auto generate a unique ID for root Entities. But what about Entities of the same Kind that have different Parents?

Will datastore auto generate unique IDs for Entities for the same Kind with different parents (of same Kind)? e.g. User->Post. Could two different Users conceivably each have a Post with the same ID?

解决方案

I wrote a JUnit test for you. It uses lombok, but you can write out the getters and setters as well.

import com.google.appengine.tools.development.testing.LocalDatastoreServiceTestConfig;
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
import com.googlecode.objectify.*;
import com.googlecode.objectify.annotation.Entity;
import com.googlecode.objectify.annotation.Id;
import com.googlecode.objectify.annotation.Parent;
import com.googlecode.objectify.util.Closeable;
import junit.framework.Assert;
import lombok.Getter;
import lombok.Setter;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

import java.util.List;

public class IdAllocationTest {
    @Entity
    public static class ChildEntity {
        @Parent
        @Getter
        @Setter
        private Ref<ParentEntity> parent;
        @Id
        @Getter
        @Setter
        private Long id;
    }

    @Entity
    public static class ParentEntity {
        @Id
        @Getter
        @Setter
        private Long id;
    }

    public static class OfyService {
        static {
            try {
                ObjectifyService.register(ChildEntity.class);
                ObjectifyService.register(ParentEntity.class);
            } catch (Exception e) {
                System.out.println("Could not initialized objectify service." + e.toString());
            }
        }

        public static Objectify ofy() {
            return ObjectifyService.ofy();
        }

        public static ObjectifyFactory factory() {
            return ObjectifyService.factory();
        }
    }

    private static LocalServiceTestHelper helper = new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig());
    private static Closeable objectifyBegin;

    @BeforeClass
    public static void beforeClass(){
        helper.setUp();
        objectifyBegin = ObjectifyService.begin();
    }

    @AfterClass
    public static void afterClass(){
        objectifyBegin.close();
        helper.tearDown();
    }

    @Test
    public void testIdAllocation() {
        Ref<ParentEntity> parent1 = Ref.create(Key.create(ParentEntity.class, 1L));
        Ref<ParentEntity> parent2 = Ref.create(Key.create(ParentEntity.class, 2L));

        ChildEntity childEntity1 = new ChildEntity();
        childEntity1.setParent(parent1);
        childEntity1.setId(1L);

        ChildEntity childEntity2 = new ChildEntity();
        childEntity2.setParent(parent2);
        childEntity2.setId(1L);

        OfyService.ofy().save().entities(childEntity1, childEntity2).now();

        List<Key<ChildEntity>> keys = OfyService.ofy().load().type(ChildEntity.class).keys().list();
        // If overwriting occurred it would be only a single entity
        Assert.assertEquals(keys.size(), 2);
        for (Key<ChildEntity> child : keys) {

            System.out.println("Key( " +
                    "Key('" + child.getParent().getKind() + "'," + child.getParent().getId() + "), " +
                    "'" + child.getKind() + "', " + child.getId() + ")");
        }

        while(true) {
            KeyRange<ChildEntity> keyRangeParent1 = OfyService.factory().allocateIds(parent1, ChildEntity.class, 100);
            KeyRange<ChildEntity> keyRangeParent2 = OfyService.factory().allocateIds(parent2, ChildEntity.class, 100);

            for (Key<ChildEntity> keyParent1 : keyRangeParent1) {
                for (Key<ChildEntity> keyParent2 : keyRangeParent2) {
                    System.out.println(keyParent1.getId() + ", " + keyParent2.getId());
                    Assert.assertTrue(keyParent1.getId() != keyParent2.getId());
                }
            }
        }
    }
}

On the devserver, the output of this unit test starts like this

Key( Key('ParentEntity',1), 'ChildEntity', 1)
Key( Key('ParentEntity',2), 'ChildEntity', 1)
1, 101
1, 102
1, 103
1, 104
1, 105

Which proofs two things:

  1. Same Id with different ancestor is possible
  2. The behaviour on the devserver is that ids won't collide (they seem to use the same counter). Basically this proofs that we can't proof a thing by looking at the devserver, but the code could (theoretically) be run on a live system.

Warning: Please don't deploy this code. There's a potenially endless loop in there and the chances of an actual hit are quite small. One would have to drastically increase the number of allocated ids and keep the allocated ids of one parent for comparison. Even then you'd hit the DeadlineExceeded and OutOfMemory exception long before you've tested all allocatedIds.

Summary: Unless someone from Google can enlightens us on how the id allocation works, there isn't much we can find out. A quick look in the Datastore implementation shows that an allocation is a request to the datastore thus there's no code that could be analyzed to dig deeper.

I guess we'll just have to trust that the documentation is right, when it says

The only way to avoid such conflicts is to have your application obtain a block of IDs with the methods DatastoreService.allocateIds() or AsyncDatastoreService.allocateIds(). The Datastore's automatic ID generator will keep track of IDs that have been allocated with these methods and will avoid reusing them for another entity, so you can safely use such IDs without conflict.

about the id allocation methods.

这篇关于如果父母不同,同一类型的两个实体是否可以拥有相同的ID?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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