我一直在探索Datanucleus框架,并尝试了文档中提供的一些示例。我使用Sets陷入了M-N关系示例。当我尝试从Set中删除一个对象时,它将从Set中删除,但是一旦我持久化容器对象,就不会删除连接表中的条目。这导致我的容器对象仍然保持被移除的对象。
我有一个暴露问题的单元测试:
@Test
public void testMNRelation() {
final Product product = new Product();
product.setName("Product 1");
product.setPrice(100);
final Product product2 = new Product();
product2.setName("Product 2");
product2.setPrice(130);
final Supplier supplier = new Supplier();
supplier.setName("Supplier 1");
Set<Supplier> suppliers = product.getSuppliers();
suppliers.add(supplier);
Set<Product> products = supplier.getProducts();
products.add(product2);
final PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory("MyStore");
PersistenceManager pm = pmf.getPersistenceManager();
Transaction tx = pm.currentTransaction();
try {
tx.begin();
pm.makePersistent(product);
pm.makePersistent(product2);
tx.commit();
} finally {
if (tx.isActive()) {
tx.rollback();
}
}
pm.close();
pm = pmf.getPersistenceManager();
tx = pm.currentTransaction();
try {
tx.begin();
System.out.println();
System.out.println("Fetch from store (before removal)");
Supplier s = pm.getObjectById(Supplier.class, supplier.getId());
System.out.println("supplier name: " + s.getName());
System.out.println("# products: " + s.getProducts().size());
Product p = pm.getObjectById(Product.class, product.getId());
System.out.println("product name: " + p.getName());
System.out.println("# suppliers: " + p.getSuppliers().size());
Product p2 = pm.getObjectById(Product.class, product2.getId());
System.out.println("product name: " + p2.getName());
System.out.println("# suppliers: " + p2.getSuppliers().size());
tx.commit();
} finally {
if (tx.isActive()) {
tx.rollback();
}
}
pm.close();
Set<Product> updatedProducts = supplier.getProducts();
updatedProducts.remove(product);
Set<Supplier> updatedSuppliers = product.getSuppliers();
updatedSuppliers.remove(supplier);
System.out.println();
System.out.println("Before persist (after removal)");
System.out.println("supplier name: " + supplier.getName());
System.out.println("# products: " + supplier.getProducts().size());
System.out.println("product name: " + product.getName());
System.out.println("# suppliers: " + product.getSuppliers().size());
System.out.println("product name: " + product2.getName());
System.out.println("# suppliers: " + product2.getSuppliers().size());
pm = pmf.getPersistenceManager();
tx = pm.currentTransaction();
try {
tx.begin();
pm.makePersistent(supplier);
pm.makePersistent(product);
tx.commit();
} finally {
if (tx.isActive()) {
tx.rollback();
}
}
pm.close();
System.out.println();
System.out.println("After persist");
System.out.println("supplier name: " + supplier.getName());
System.out.println("# products: " + supplier.getProducts().size());
System.out.println("product name: " + product.getName());
System.out.println("# suppliers: " + product.getSuppliers().size());
System.out.println("product name: " + product2.getName());
System.out.println("# suppliers: " + product2.getSuppliers().size());
pm = pmf.getPersistenceManager();
tx = pm.currentTransaction();
try {
tx.begin();
System.out.println();
System.out.println("Fetch from store");
Supplier s = pm.getObjectById(Supplier.class, supplier.getId());
System.out.println("supplier name: " + s.getName());
System.out.println("# products: " + s.getProducts().size());
Product p = pm.getObjectById(Product.class, product.getId());
System.out.println("product name: " + p.getName());
System.out.println("# suppliers: " + p.getSuppliers().size());
Product p2 = pm.getObjectById(Product.class, product2.getId());
System.out.println("product name: " + p2.getName());
System.out.println("# suppliers: " + p2.getSuppliers().size());
tx.commit();
} finally {
if (tx.isActive()) {
tx.rollback();
}
}
pm.close();
}
http://www.datanucleus.org/products/datanucleus/jdo/orm/many_to_many.html
示例中使用的2种类型@PersistenceCapable(detachable="true")
public class Supplier {
@PrimaryKey
@Persistent(valueStrategy=IdGeneratorStrategy.INCREMENT)
private long id;
@Persistent
private String name;
@Persistent(mappedBy="suppliers")
private Set<Product> products = new HashSet<Product>();
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Product> getProducts() {
return products;
}
public void setProducts(Set<Product> products) {
this.products = products;
}
@Override
public boolean equals(Object o) {
if(this.getId() == 0) {
return false;
}
if(o instanceof Supplier) {
Supplier other = (Supplier) o;
return this.getId() == other.getId();
}
return false;
}
@Override
public int hashCode() {
return Long.toString(this.getId()).hashCode();
}
}
和
@PersistenceCapable(detachable="true")
public class Product {
@PrimaryKey
@Persistent(valueStrategy=IdGeneratorStrategy.INCREMENT)
private long id;
@Persistent
private String name;
@Persistent
private double price;
@Persistent(table="PRODUCTS_SUPPLIERS")
@Join(column="PRODUCT_ID")
@Element(column="SUPPLIER_ID")
private Set<Supplier> suppliers = new HashSet<Supplier>();
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public Set<Supplier> getSuppliers() {
return suppliers;
}
public void setSuppliers(Set<Supplier> suppliers) {
this.suppliers = suppliers;
}
@Override
public boolean equals(Object o) {
if(getId() == 0) {
return false;
}
if(o instanceof Product) {
Product other = (Product) o;
return this.getId() == other.getId();
}
return false;
}
@Override
public int hashCode() {
return Long.toString(this.getId()).hashCode();
}
}
现在,在控制台中我得到了
Fetch from store (before removal)
supplier name: Supplier 1
# products: 2
product name: Product 1
# suppliers: 1
product name: Product 2
# suppliers: 1
Before persist (after removal)
supplier name: Supplier 1
# products: 1
product name: Product 1
# suppliers: 0
product name: Product 2
# suppliers: 1
After persist
supplier name: Supplier 1
# products: 1
product name: Product 1
# suppliers: 1
product name: Product 2
# suppliers: 1
Fetch from store
supplier name: Supplier 1
# products: 1
product name: Product 1
# suppliers: 1
product name: Product 2
# suppliers: 1
我希望像
这样的东西Fetch from store (before removal)
supplier name: Supplier 1
# products: 2
product name: Product 1
# suppliers: 1
product name: Product 2
# suppliers: 1
Before persist (after removal)
supplier name: Supplier 1
# products: 1
product name: Product 1
# suppliers: 0
product name: Product 2
# suppliers: 1
After persist
supplier name: Supplier 1
# products: 1
product name: Product 1
# suppliers: 0
product name: Product 2
# suppliers: 1
Fetch from store
supplier name: Supplier 1
# products: 1
product name: Product 1
# suppliers: 0
product name: Product 2
# suppliers: 1
我的persistence.xml包括:
<property name="datanucleus.DetachAllOnCommit" value="true" />
<property name="datanucleus.attachSameDatastore" value="true" />
<property name="datanucleus.CopyOnAttach" value="false" />
<property name="datanucleus.cache.collections.lazy" value="true" />
<property name="datanucleus.manageRelationships" value="true" />
<property name="datanucleus.manageRelationshipsChecks" value="true" />
关于如何解决这个问题的任何想法?
答案 0 :(得分:0)
我已经找到了解决问题的方法。这个问题似乎与我的持久性设置有关。我将设置更改为
<property name="datanucleus.DetachAllOnCommit" value="true" />
<property name="datanucleus.attachSameDatastore" value="true" />
<property name="datanucleus.CopyOnAttach" value="true" />
<property name="datanucleus.cache.collections.lazy" value="true" />
<property name="datanucleus.manageRelationships" value="false" />
<property name="datanucleus.manageRelationshipsChecks" value="false" />
<property name="datanucleus.persistenceByReachabilityAtCommit" value="false" />
因为我现在在我的实现中处理关系的两个方面。
此外,我实施了一个工厂来简化我的测试
public class Factory {
private static final PersistenceManagerFactory pmf = get();
private static PersistenceManagerFactory get() {
return JDOHelper.getPersistenceManagerFactory("MyStore");
}
public static Product buildProduct(String name, double price) {
Product product = new Product();
product.setName(name);
product.setPrice(price);
save(product);
return product;
}
public static Supplier buildSupplier(String name) {
Supplier supplier = new Supplier();
supplier.setName(name);
save(supplier);
return supplier;
}
public static void addRelation(final Supplier supplier, final Product product) {
product.getSuppliers().add(supplier);
supplier.getProducts().add(product);
save(product, supplier);
}
public static void removeRelation(Supplier supplier, Product product) {
product.getSuppliers().remove(supplier);
supplier.getProducts().remove(product);
save(product, supplier);
}
public static Product loadProduct(long id) {
return (Product) load(Product.class, id);
}
public static Supplier loadSupplier(long id) {
return (Supplier) load(Supplier.class, id);
}
private static void save(final Object... objects) {
PersistenceManager pm = pmf.getPersistenceManager();
Transaction tx = pm.currentTransaction();
try {
tx.begin();
pm.makePersistentAll(objects);
tx.commit();
} finally {
if (tx.isActive()) {
tx.rollback();
}
}
pm.close();
}
private static Object load(Class<?> clazz, long id) {
final Object[] result = new Object[1];
PersistenceManager pm = pmf.getPersistenceManager();
Transaction tx = pm.currentTransaction();
try {
tx.begin();
result[0] = pm.getObjectById(clazz, id);
tx.commit();
} finally {
if (tx.isActive()) {
tx.rollback();
}
}
pm.close();
if (result[0] == null) {
throw new NoSuchElementException(clazz.getSimpleName() + " with id=" + id + " cannot be found");
}
return result[0];
}
}
所以测试只是表示为
@Test
public void testFactoryApproach() {
Product p1 = Factory.buildProduct("product1", 50);
Product p2 = Factory.buildProduct("product2", 70);
Supplier s1 = Factory.buildSupplier("Supplier1");
System.out.println("Initial:");
System.out.println(p1);
System.out.println(p2);
System.out.println(s1);
System.out.println();
Factory.addRelation(s1, p1);
Factory.addRelation(s1, p2);
System.out.println("Relations after add:");
System.out.println(p1);
System.out.println(p2);
System.out.println(s1);
System.out.println();
Factory.removeRelation(s1, p1);
System.out.println("Relations after remove:");
System.out.println(p1);
System.out.println(p2);
System.out.println(s1);
System.out.println();
System.out.println("Relations after load:");
System.out.println(Factory.loadProduct(p1.getId()));
System.out.println(Factory.loadProduct(p2.getId()));
System.out.println(Factory.loadSupplier(s1.getId()));
}
以下输出结果
Initial:
Product:11 (product1) - # suppliers = 0 []
Product:12 (product2) - # suppliers = 0 []
Supplier:11 (Supplier1) - # products = 0 []
Relations after add:
Product:11 (product1) - # suppliers = 1 [11:Supplier1]
Product:12 (product2) - # suppliers = 1 [11:Supplier1]
Supplier:11 (Supplier1) - # products = 2 [11:product1, 12:product2]
Relations after remove:
Product:11 (product1) - # suppliers = 0 []
Product:12 (product2) - # suppliers = 1 [11:Supplier1]
Supplier:11 (Supplier1) - # products = 1 [12:product2]
Relations after load:
Product:11 (product1) - # suppliers = 0 []
Product:12 (product2) - # suppliers = 1 [11:Supplier1]
Supplier:11 (Supplier1) - # products = 1 [12:product2]