我试图使用JPA2元数据来确定从数据库中插入/删除行的顺序,这样约束就不会成为问题(稍后将在Java代码中使用)。这是使用JPA的备份/还原方法的一部分。
我的方法是:
就绪的意思是,它的所有相关表记录都被填充,所以外键对于insert是有效的,或者没有其他表引用该表中的记录。
我确信这将是某种递归方法,但我被卡住了。任何帮助都是受欢迎的。
以下是目前为止的代码:
/**
* Get the execution order from the EntityManager meta data model.
*
* This will fail if the EntityManager is not JP2 compliant
* @param em EntityManager to get the metadata from
* @return ArrayList containing the order to process tables
*/
protected static ArrayList<String> getProcessingOrder(EntityManager em) {
ArrayList<String> tables = new ArrayList<String>();
//This holds the amount of relationships and the tables with that same amount
HashMap<Integer, ArrayList<String>> tableStats = new HashMap<Integer, ArrayList<String>>();
//This holds the table and the tables referenced by it
HashMap<String, ArrayList<String>> references = new HashMap<String, ArrayList<String>>();
for (EntityType et : em.getMetamodel().getEntities()) {
Logger.getLogger(XincoBackupManager.class.getSimpleName()).log(Level.FINER, et.getName());
int amount = 0;
Iterator<SingularAttribute> sIterator = et.getSingularAttributes().iterator();
while (sIterator.hasNext()) {
SingularAttribute next = sIterator.next();
switch (next.getPersistentAttributeType()) {
case BASIC:
case ELEMENT_COLLECTION:
case EMBEDDED:
case ONE_TO_MANY:
case ONE_TO_ONE:
Logger.getLogger(XincoBackupManager.class.getSimpleName()).log(Level.FINER,
"Ignoring: {0}", next.getName());
break;
case MANY_TO_MANY:
case MANY_TO_ONE:
Logger.getLogger(XincoBackupManager.class.getSimpleName()).log(Level.INFO,
"{3} has a {2} relationship: {0} with: {1}",
new Object[]{next.getName(), next.getBindableJavaType(),
next.getPersistentAttributeType().name(), et.getName()});
if (!references.containsKey(et.getName())) {
references.put(et.getName(), new ArrayList<String>());
}
references.get(et.getName()).add(next.getBindableJavaType().getSimpleName());
amount++;
break;
default:
Logger.getLogger(XincoBackupManager.class.getSimpleName()).log(Level.SEVERE,
"Unexpected value: {0}", next.getName());
break;
}
}
Iterator<PluralAttribute> pIterator = et.getPluralAttributes().iterator();
while (pIterator.hasNext()) {
PluralAttribute next = pIterator.next();
switch (next.getPersistentAttributeType()) {
case BASIC:
case ELEMENT_COLLECTION:
case EMBEDDED:
case ONE_TO_MANY:
case MANY_TO_MANY:
Logger.getLogger(XincoBackupManager.class.getSimpleName()).log(Level.FINER,
"Ignoring: {0}", next.getName());
break;
case MANY_TO_ONE:
case ONE_TO_ONE:
Logger.getLogger(XincoBackupManager.class.getSimpleName()).log(Level.INFO,
"{3} has a {2} relationship: {0} with: {1}",
new Object[]{next.getName(), next.getBindableJavaType(),
next.getPersistentAttributeType().name(), et.getName()});
if (!references.containsKey(et.getName())) {
references.put(et.getName(), new ArrayList<String>());
}
references.get(et.getName()).add(next.getBindableJavaType().getSimpleName());
amount++;
break;
default:
Logger.getLogger(XincoBackupManager.class.getSimpleName()).log(Level.SEVERE,
"Unexpected value: {0}", next.getName());
break;
}
}
if (!tableStats.containsKey(amount)) {
tableStats.put(amount, new ArrayList<String>());
}
tableStats.get(amount).add(et.getName());
}
Iterator<String> iterator = references.keySet().iterator();
while (iterator.hasNext()) {
String next = iterator.next();
Iterator<String> iterator1 = references.get(next).iterator();
StringBuilder refs = new StringBuilder();
while (iterator1.hasNext()) {
refs.append(iterator1.next()).append("\n");
}
Logger.getLogger(XincoBackupManager.class.getSimpleName()).log(Level.FINER, "References for {0}:\n{1}", new Object[]{next, refs.toString()});
}
//Need to sort entities with relationships even further
ArrayList<String> temp = new ArrayList<String>();
for (Entry<Integer, ArrayList<String>> e : tableStats.entrySet()) {
if (e.getKey() > 0) {
Logger.getLogger(XincoBackupManager.class.getSimpleName()).log(Level.INFO, "Tables with {0} references", e.getKey());
for (String t : e.getValue()) {
//Check the relationships of the tables
//Here's where I need help
boolean ready = true;
for (String ref : references.get(t)) {
if (!temp.contains(ref)) {
Logger.getLogger(XincoBackupManager.class.getSimpleName()).log(Level.INFO,
"{0} is not ready. Referenced table {1} is not ready yet", new Object[]{t, ref});
ready = false;
}
}
if (ready) {
Logger.getLogger(XincoBackupManager.class.getSimpleName()).log(Level.INFO, "{0} is ready.", t);
temp.add(t);
}
}
//-------------------------------------------------------
} else {
temp.addAll(e.getValue());
}
}
for (Entry<Integer, ArrayList<String>> e : tableStats.entrySet()) {
Logger.getLogger(XincoBackupManager.class.getSimpleName()).log(Level.FINER,
"Amount of relationships: {0}", e.getKey());
StringBuilder list = new StringBuilder();
for (String t : e.getValue()) {
list.append(t).append("\n");
}
Logger.getLogger(XincoBackupManager.class.getSimpleName()).log(Level.FINER, list.toString());
}
tables.addAll(temp);
return tables;
}发布于 2010-07-21 12:28:11
我会用JDBC的数据库元数据来解决这个问题。
这里将使用来自java.sql.DatabaseMetadata的下列方法:
// to get the tables
getTables(String catalog, String schemaPattern, String tableNamePattern, String[] types)
// to get the reference to the table
public ResultSet getExportedKeys(String catalog,
String schema,
String table)
throws SQLException我在几个应用程序中都使用了这种方法,它工作得很好。
尽管这种方法不遵循JPA元模型的用法,但考虑到您的问题,我认为在JDBC元数据级别上操作更为合适。
由于可能存在循环依赖项,很难通过这样的外键依赖关系图来处理,因此您可以另外选择。
删除
用于添加
https://stackoverflow.com/questions/3294055
复制相似问题