public TraceObjectBreakpointLocation addBreakpoint(String path, Lifespan lifespan,
			AddressRange range, Collection<TraceThread> threads,
			Collection<TraceBreakpointKind> kinds, boolean enabled, String comment)
			throws DuplicateNameException {
		// First verify that the schema accommodates
		KeyPath specPath = getRootSchema().searchForAncestor(TraceObjectBreakpointSpec.class,
			KeyPath.parse(path));
		if (specPath == null) {
			throw new IllegalStateException("The schema does not provide an implicit " +
				"breakpoint specification on the given path.");
		}
		try (LockHold hold = trace.lockWrite()) {
			DBTraceObjectBreakpointLocation loc =
				(DBTraceObjectBreakpointLocation) doAddWithInterface(path,
					TraceObjectBreakpointLocation.class);
			loc.setName(lifespan, path);
			loc.setRange(lifespan, range);
			loc.setEnabled(lifespan, enabled);
			loc.setComment(lifespan, comment);

			TraceObjectBreakpointSpec spec = loc.getOrCreateSpecification();
			// NB. Ignore threads. I'd like to deprecate that field, anyway.
			spec.setKinds(lifespan, kinds);
			loc.getObject().insert(lifespan, ConflictResolution.DENY);
			return loc;
		}
		catch (DuplicateKeyException e) {
			throw new DuplicateNameException(e.getMessage());
		}
	}
NB. An object in one of these queries had to have an edge. Deleting that object will also
delete referring edges, so the cache will get invalidated. No need to repeat in
doDeleteObject.
Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/target/DBTraceObjectManager.java