In deel 1 leerden we de basis van FindFilesBySearchConditions: verbinding maken, zoeken op naam en eigenschap, condities combineren en paginering. In dit tweede deel gaan we dieper in op geavanceerde technieken die je zoekopdrachten krachtiger, sneller en herbruikbaarder maken.
OR en NOT logica met SearchRuleType
In deel 1 gebruikten we alleen SearchRuleType.Must (AND). Vault ondersteunt drie regels:
- Must — het bestand MOET aan deze conditie voldoen (AND)
- May — het bestand MAG aan deze conditie voldoen — meerdere May-condities vormen OR-logica
- MustNot — het bestand mag NIET aan deze conditie voldoen (NOT/uitsluiten)
De combinatieformule is: (alle Must-condities) EN (minstens één May-conditie). MustNot sluit bestanden uit die aan de conditie voldoen.
// Zoek alle tekeningen (.dwg of .idw) in project PROJ-001
// die NIET de status "Obsolete" hebben
long statusId = GetPropId("State"); // zie "PropDefId-waarden cachen" hieronder
// Must: naam begint met het projectnummer
var condProject = new SrchCond
{
PropDefId = 0, PropTyp = PropertySearchType.AllProperties,
SrchOper = 4, // begint met
SrchTxt = "PROJ-001",
SrchRule = SearchRuleType.Must
};
// May: eindigt op .dwg OF .idw (OR via May)
var condDwg = new SrchCond
{
PropDefId = 0, PropTyp = PropertySearchType.AllProperties,
SrchOper = 5, SrchTxt = ".dwg",
SrchRule = SearchRuleType.May
};
var condIdw = new SrchCond
{
PropDefId = 0, PropTyp = PropertySearchType.AllProperties,
SrchOper = 5, SrchTxt = ".idw",
SrchRule = SearchRuleType.May
};
// MustNot: sluit verouderde bestanden uit
var condNietObsolete = new SrchCond
{
PropDefId = statusId, PropTyp = PropertySearchType.SingleProperty,
SrchOper = 1, SrchTxt = "Obsolete",
SrchRule = SearchRuleType.MustNot
};
string bm = string.Empty; SrchStatus st;
var resultaten = docSvc.FindFilesBySearchConditions(
new[] { condProject, condDwg, condIdw, condNietObsolete },
null, null, true, true, ref bm, out st);
Zoeken op bestandsextensie
Vault heeft geen aparte eigenschap voor extensies. Gebruik SrchOper = 5 (eindigt op) op de bestandsnaam (PropDefId = 0). Combineer meerdere extensies met May voor OR-logica:
// Alle Inventor-bestanden (.ipt, .iam, .idw) ophalen
var condIpt = new SrchCond
{
PropDefId = 0, PropTyp = PropertySearchType.AllProperties,
SrchOper = 5, SrchTxt = ".ipt",
SrchRule = SearchRuleType.May
};
var condIam = new SrchCond
{
PropDefId = 0, PropTyp = PropertySearchType.AllProperties,
SrchOper = 5, SrchTxt = ".iam",
SrchRule = SearchRuleType.May
};
var condIdw = new SrchCond
{
PropDefId = 0, PropTyp = PropertySearchType.AllProperties,
SrchOper = 5, SrchTxt = ".idw",
SrchRule = SearchRuleType.May
};
// Resultaat: alle .ipt, .iam en .idw bestanden (vault-breed)
string bm = string.Empty; SrchStatus st;
var inventorBestanden = docSvc.FindFilesBySearchConditions(
new[] { condIpt, condIam, condIdw },
null, null, true, true, ref bm, out st);
Zoeken op datumbereik
Vault bewaart de mutatiedatum als een reguliere eigenschap ("Date Modified"). Gebruik twee condities met operator 8 (≥) en 9 (≤) om een bereik te definiëren.
Belangrijk: Vault verwacht datums altijd in Amerikaans formaat (M/d/yyyy h:mm:ss tt), ook op Nederlandstalige systemen. Gebruik het expliciete formaatstring om problemen te voorkomen.
// Zoek alle bestanden aangepast in de afgelopen 30 dagen
long datumId = GetPropId("Date Modified");
// Altijd US-datumformaat gebruiken
string vanDatum = DateTime.Now.AddDays(-30)
.ToString("M/d/yyyy h:mm:ss tt");
string totDatum = DateTime.Now
.ToString("M/d/yyyy h:mm:ss tt");
var condVan = new SrchCond
{
PropDefId = datumId,
PropTyp = PropertySearchType.SingleProperty,
SrchOper = 8, // groter dan of gelijk aan (>=)
SrchTxt = vanDatum,
SrchRule = SearchRuleType.Must
};
var condTot = new SrchCond
{
PropDefId = datumId,
PropTyp = PropertySearchType.SingleProperty,
SrchOper = 9, // kleiner dan of gelijk aan (<=)
SrchTxt = totDatum,
SrchRule = SearchRuleType.Must
};
string bm = string.Empty; SrchStatus st;
var gewijzigd = docSvc.FindFilesBySearchConditions(
new[] { condVan, condTot },
null, null, true, true, ref bm, out st);
Console.WriteLine(
$"{gewijzigd?.Length ?? 0} bestanden gewijzigd in de afgelopen 30 dagen.");
Meerdere mappen tegelijk doorzoeken
FindFilesBySearchConditions accepteert een array van map-ID's, zodat je meerdere mappen in één aanroep kunt doorzoeken:
// Zoek in meerdere projectmappen en de standaardenbibliotheek
var mapPaden = new[]
{
"$/Projecten/PROJ-001",
"$/Projecten/PROJ-002",
"$/Bibliotheek/Standaardonderdelen"
};
// Mappen ophalen en niet-bestaande overslaan
long[] mapIds = mapPaden
.Select(pad => docSvc.GetFolderByPath(pad))
.Where(m => m != null) // niet-bestaande mappen overslaan
.Select(m => m.Id)
.ToArray();
if (mapIds.Length == 0)
throw new Exception("Geen van de opgegeven mappen gevonden.");
string bm = string.Empty; SrchStatus st;
var resultaten = docSvc.FindFilesBySearchConditions(
new[] { cond },
null,
mapIds, // array van meerdere map-ID's
true, true, ref bm, out st);
PropDefId-waarden cachen
Elke aanroep van GetPropertyDefinitionsByDomainAndEntityClassId kost een netwerkrondreis naar de Vault-server. Als je meerdere zoekopdrachten uitvoert, cache de ID-waarden dan eenmalig bij opstarten:
// Eenmalig aanroepen bij applicatiestart (bijv. na Connect())
private static Dictionary<string, long> _propCache;
public static void InitPropCache(WebServiceManager wsm)
{
var defs = wsm.PropertyService
.GetPropertyDefinitionsByDomainAndEntityClassId("FILE", "FILE");
// Indexeer op weergavenaam, hoofdletterongevoelig
_propCache = defs?.ToDictionary(
d => d.DispName,
d => d.Id,
StringComparer.OrdinalIgnoreCase)
?? new Dictionary<string, long>(StringComparer.OrdinalIgnoreCase);
}
// Opzoeken zonder extra API-aanroep
public static long GetPropId(string naam)
{
if (_propCache.TryGetValue(naam, out long id)) return id;
throw new KeyNotFoundException(
$"Eigenschap '{naam}' niet gevonden. " +
"Controleer de naam in Vault of roep InitPropCache opnieuw aan.");
}
// Na InitPropCache() zijn alle zoekopdrachten in dezelfde sessie snel:
long revId = GetPropId("Revision Number");
long statusId = GetPropId("State");
long datumId = GetPropId("Date Modified");
iProperties ophalen na zoekoperatie
Een zoekresultaat bevat basisvelden (Name, Id, VerNum, FullPath), maar geen iProperties. Die haal je op met GetPropertiesByEntityIds — in één API-aanroep voor alle gevonden bestanden tegelijk:
// Stap 1: zoekopdracht uitvoeren
var bestanden = ZoekAlleResultaten(docSvc, new[] { cond });
if (bestanden.Count == 0) return;
// Stap 2: welke eigenschappen wil je ophalen?
long[] propIds = new[]
{
GetPropId("Revision Number"),
GetPropId("Part Number"),
GetPropId("Description"),
GetPropId("State")
};
// Stap 3: alle iProperties in één aanroep ophalen
// GetPropertiesByEntityIds(domain, entityClassId, propDefIds, entityIds)
long[] bestandIds = bestanden.Select(f => f.Id).ToArray();
PropInst[] eigenschappen = conn.WebServiceManager.PropertyService
.GetPropertiesByEntityIds("FILE", "FILE", propIds, bestandIds);
// Stap 4: eigenschappen per bestand groeperen op EntityId
var perBestand = eigenschappen
.GroupBy(p => p.EntityId)
.ToDictionary(g => g.Key, g => g.ToList());
// Stap 5: combineren en tonen
foreach (var bestand in bestanden)
{
Console.Write($"{bestand.Name,-40}");
if (perBestand.TryGetValue(bestand.Id, out var props))
foreach (var prop in props)
Console.Write($" [{prop.Val}]");
Console.WriteLine();
}
Herbruikbare VaultSearchHelper klasse
De volgende klasse bundelt alle bovenstaande patronen in een herbruikbare interface. De klasse cached PropDefId-waarden automatisch bij aanmaak en handelt paginering intern af:
using Autodesk.Connectivity.WebServices;
using Autodesk.Connectivity.WebServicesTools;
/// <summary>
/// Herbruikbare hulpklasse voor Vault-bestandszoekopdrachten.
///
/// Gebruik:
/// var helper = new VaultSearchHelper(conn.WebServiceManager);
/// var bestanden = helper.ZoekOpEigenschap("Revision Number", "A", mapIds);
///
/// De klasse cached eigenschap-ID's eenmalig bij aanmaak om
/// herhaalbare API-aanroepen te vermijden, en handelt paginering
/// automatisch af. Geeft nooit null terug.
/// </summary>
public class VaultSearchHelper
{
private readonly DocumentService _docSvc;
private readonly Dictionary<string, long> _propCache;
public VaultSearchHelper(WebServiceManager wsm)
{
_docSvc = wsm.DocumentService;
// Alle eigenschapsdefinities ophalen en op naam indexeren
var defs = wsm.PropertyService
.GetPropertyDefinitionsByDomainAndEntityClassId("FILE", "FILE");
_propCache = defs?.ToDictionary(
d => d.DispName,
d => d.Id,
StringComparer.OrdinalIgnoreCase)
?? new Dictionary<string, long>(StringComparer.OrdinalIgnoreCase);
}
// ── Interne hulpmethoden ───────────────────────────────────────────────
/// <summary>Geeft de PropDefId op naam, of gooit KeyNotFoundException.</summary>
public long GetPropId(string naam)
{
if (_propCache.TryGetValue(naam, out long id)) return id;
throw new KeyNotFoundException(
$"Eigenschap '{naam}' niet gevonden in Vault.");
}
/// <summary>
/// Kernmethode: voert een zoekopdracht uit met automatische paginering.
/// Vault geeft max. 200 resultaten per aanroep; deze methode haalt alles op.
/// </summary>
public List<File> Zoek(
SrchCond[] condities,
long[] mapIds = null,
bool inclSubmappen = true,
bool latestOnly = true)
{
var resultaat = new List<File>();
string bookmark = string.Empty;
SrchStatus status;
do
{
var batch = _docSvc.FindFilesBySearchConditions(
condities, null, mapIds,
inclSubmappen, latestOnly,
ref bookmark, out status);
if (batch != null)
resultaat.AddRange(batch);
}
while (status != null && status.TotalHits > resultaat.Count);
return resultaat;
}
// ── Snelkoppelingen ────────────────────────────────────────────────────
/// <summary>Bestanden waarvan de naam de opgegeven tekst bevat.</summary>
public List<File> ZoekOpNaam(string tekst, long[] mapIds = null)
=> Zoek(new[] { new SrchCond {
PropDefId = 0, PropTyp = PropertySearchType.AllProperties,
SrchOper = 3, SrchTxt = tekst,
SrchRule = SearchRuleType.Must } }, mapIds);
/// <summary>Bestanden met een exacte eigenschapswaarde.</summary>
public List<File> ZoekOpEigenschap(
string eigenschap, string waarde, long[] mapIds = null)
=> Zoek(new[] { new SrchCond {
PropDefId = GetPropId(eigenschap),
PropTyp = PropertySearchType.SingleProperty,
SrchOper = 1, SrchTxt = waarde,
SrchRule = SearchRuleType.Must } }, mapIds);
/// <summary>
/// Bestanden aangepast binnen een datumbereik.
/// Vault-datumformaat (US) wordt automatisch toegepast.
/// </summary>
public List<File> ZoekOpDatumBereik(
DateTime van, DateTime tot, long[] mapIds = null)
{
long datumId = GetPropId("Date Modified");
string vanStr = van.ToString("M/d/yyyy h:mm:ss tt");
string totStr = tot.ToString("M/d/yyyy h:mm:ss tt");
return Zoek(new[]
{
new SrchCond { PropDefId = datumId,
PropTyp = PropertySearchType.SingleProperty,
SrchOper = 8, SrchTxt = vanStr,
SrchRule = SearchRuleType.Must }, // >=
new SrchCond { PropDefId = datumId,
PropTyp = PropertySearchType.SingleProperty,
SrchOper = 9, SrchTxt = totStr,
SrchRule = SearchRuleType.Must } // <=
}, mapIds);
}
/// <summary>
/// Bestanden met een van de opgegeven extensies (.dwg, .ipt, ...).
/// Geef extensies mee met of zonder punt — beide worden geaccepteerd.
/// </summary>
public List<File> ZoekOpExtensie(
string[] extensies, long[] mapIds = null)
{
if (extensies == null || extensies.Length == 0)
throw new ArgumentException("Geef minstens één extensie op.");
// Elke extensie = één May-conditie (OR-logica)
var condities = extensies.Select(ext => new SrchCond
{
PropDefId = 0,
PropTyp = PropertySearchType.AllProperties,
SrchOper = 5, // eindigt op
SrchTxt = ext.StartsWith(".") ? ext : "." + ext,
SrchRule = SearchRuleType.May
}).ToArray();
return Zoek(condities, mapIds);
}
}
// ── Gebruik ────────────────────────────────────────────────────────────────
var helper = new VaultSearchHelper(conn.WebServiceManager);
// Map-ID ophalen (eenmalig)
var map = conn.WebServiceManager.DocumentService
.GetFolderByPath("$/Projecten/PROJ-001");
var mapIds = map != null ? new[] { map.Id } : null;
// Voorbeelden
var onderdelen = helper.ZoekOpExtensie(new[] { ".ipt", ".iam" }, mapIds);
var revA = helper.ZoekOpEigenschap("Revision Number", "A", mapIds);
var recent = helper.ZoekOpDatumBereik(DateTime.Now.AddDays(-7), DateTime.Now);
Console.WriteLine($"{onderdelen.Count} Inventor-bestanden in PROJ-001");
Console.WriteLine($"{revA.Count} bestanden met revisie A");
Console.WriteLine($"{recent.Count} bestanden gewijzigd afgelopen week");
Resultaten exporteren naar CSV
/// <summary>
/// Exporteert zoekresultaten naar een CSV-bestand voor verwerking in
/// Excel, Power BI of een rapportagetool.
/// </summary>
public static void ExporteerNaarCsv(
List<File> bestanden, string uitvoerPad)
{
using var schrijver = new System.IO.StreamWriter(
uitvoerPad, false, System.Text.Encoding.UTF8);
// Koptekstregel
schrijver.WriteLine(
"Naam;Versie;Volledig pad;Grootte (bytes);Lifecyclestatus");
foreach (var b in bestanden)
{
// Puntkomma in veldwaarden ontsnappen
string naam = (b.Name ?? "").Replace(";", ",");
string pad = (b.FullPath ?? "").Replace(";", ",");
string status = b.FileLfCyc?.LfCycStateName ?? "n.v.t.";
schrijver.WriteLine(
$"{naam};{b.VerNum};{pad};{b.FileSize};{status}");
}
Console.WriteLine($"CSV geëxporteerd: {uitvoerPad}");
Console.WriteLine($"Totaal: {bestanden.Count} regels");
}
// Gebruik:
var vrijgegeven = helper.ZoekOpEigenschap("State", "Released");
ExporteerNaarCsv(vrijgegeven, @"C:\Temp\vault-released.csv");
Geavanceerde valkuilen
Alleen May-condities zonder Must — als je uitsluitend May-condities opgeeft, geeft Vault alle bestanden terug die aan minstens één conditie voldoen. Dat kan een onverwacht grote resultatenset opleveren (soms de volledige vault). Voeg altijd een Must-conditie toe als anker.
US-datumformaat vergeten — Vault verwacht datumwaarden in M/d/yyyy h:mm:ss tt (Amerikaans formaat). Op een Nederlandstalig systeem geeft DateTime.ToString() een Nederlands formaat, wat Vault niet herkent. Het resultaat: een stille lege resultatenset zonder foutmelding. Gebruik altijd het expliciete formaatstring.
GetFolderByPath geeft null terug — als het mappad niet bestaat (bijv. door een tikfout of hoofdletterverschil), geeft GetFolderByPath null terug. Als je die null rechtstreeks doorgeeft als mapfilter, zoekt Vault vault-breed in plaats van te melden dat de map niet bestaat. Controleer altijd het resultaat.
PropDefId hardcoden — eigenschap-ID's zijn niet stabiel tussen Vault-installaties. Een ID die op jouw testomgeving werkt, kan op de productieomgeving anders zijn. Gebruik altijd PropertyService of de gecachte variant in VaultSearchHelper om ID's dynamisch op te zoeken.
MustNot vergeten te testen — MustNot werkt pas correct als er ook Must-condities zijn. Zonder Must-condities kan het gedrag per Vault-versie iets variëren. Test altijd de combinatie met een kleine bekende dataset.
Verbinding verloopt bij langlopende processen — de standaard Vault-sessie verloopt na inactiviteit. Voeg bij batchoperaties over duizenden bestanden een herverbindingslogica toe of vernieuw de sessie periodiek.
Samenvatting
In dit tweede deel hebben we de basiskennis uit deel 1 uitgebreid met technieken die je Vault-zoekopdrachten naar een hoger niveau tillen: OR/NOT-logica via SearchRuleType.May en MustNot, datumbereiken, extensiefilters, meerdere mappen tegelijk, gecachte PropDefId's, iProperties ophalen in één aanroep, en een herbruikbare VaultSearchHelper-klasse. Combineer deze bouwstenen naar behoefte voor vrijwel elk zoekscenario dat je in Vault-automatisering tegenkomt.
Comments
No comments yet — be the first!
Leave a comment
Sign in to skip moderation — anonymous comments are reviewed before appearing.