/// <exception cref="InvalidOperationException">Missed secondary key for some criterion.</exception> public virtual IEnumerable <DatabaseEntry> GetByJoin(IBDbEntityInfo info, ICollection <IDataCriterion> criteria) { var cursorsLength = 0; var secondaryCursors = new SecondaryCursor[criteria.Count]; JoinCursor joinCursor = null; try { var primaryDb = _schema.GetPrimaryDb(info.EntityName); foreach (var criterion in criteria) { SecondaryKeyAttribute secondaryKey; if (!info.SecondaryKeys.TryGetValue(criterion.Name, out secondaryKey)) { var msg = $"Missed secondaty key '{criterion.Name}' for entity {info.EntityName} ({info.EntityType})."; Log.TraceEvent(TraceEventType.Critical, msg); throw new InvalidOperationException(msg); } var secondaryDb = _schema.GetSecondaryDb(primaryDb, secondaryKey); var cursor = secondaryDb.SecondaryCursor(); secondaryCursors[cursorsLength++] = cursor; var key = new DatabaseEntry(criterion.Value.ToBinnary()); if (!cursor.Move(key, exact:true)) { yield break; } } joinCursor = primaryDb.Join(secondaryCursors, true); while (joinCursor.MoveNext()) { yield return(joinCursor.Current.Value); } } finally { joinCursor?.Close(); for (var i = 0; i < cursorsLength; i++) { secondaryCursors[i].Close(); } } }
public void TestMoveJoinCursor() { testName = "TestMoveJoinCursor"; SetUpTest(true); string dbFileName = testHome + "/" + testName + ".db"; string secFileName1 = testHome + "/" + "sec_" + testName + "1.db"; string secFileName2 = testHome + "/" + "sec_" + testName + "2.db"; // Open a primary database. BTreeDatabaseConfig dbCfg = new BTreeDatabaseConfig(); dbCfg.Creation = CreatePolicy.IF_NEEDED; BTreeDatabase db = BTreeDatabase.Open(dbFileName, dbCfg); /* * Open a secondary database on high byte of * its data and another secondary database on * little byte of its data. */ SecondaryBTreeDatabase secDB1, secDB2; SecondaryCursor[] cursors = new SecondaryCursor[2]; byte[] byteValue = new byte[1]; byteValue[0] = 0; GetSecCursor(db, secFileName1, new SecondaryKeyGenDelegate(KeyGenOnBigByte), out secDB1, out cursors[0], false, new DatabaseEntry(byteValue)); byteValue[0] = 1; GetSecCursor(db, secFileName2, new SecondaryKeyGenDelegate(KeyGenOnLittleByte), out secDB2, out cursors[1], true, new DatabaseEntry(byteValue)); // Get join cursor. JoinCursor joinCursor = db.Join(cursors, true); /* * MoveNextJoinItem do not use data value found * in all of the cursor so the data in Current won't be * changed. */ Assert.IsTrue(joinCursor.MoveNextItem()); Assert.AreEqual(0, joinCursor.Current.Key.Data[ joinCursor.Current.Key.Data.Length - 1]); Assert.AreEqual(1, joinCursor.Current.Key.Data[0]); Assert.IsNull(joinCursor.Current.Value.Data); // Iterate on join cursor. foreach (KeyValuePair <DatabaseEntry, DatabaseEntry> pair in joinCursor) { /* * Confirm that the key got by join cursor has 0 at * its highest byte and 1 at its lowest byte. */ Assert.AreEqual(0, pair.Key.Data[pair.Key.Data.Length - 1]); Assert.AreEqual(1, pair.Key.Data[0]); } Assert.IsFalse(joinCursor.MoveNext()); // Close all. joinCursor.Close(); cursors[0].Close(); cursors[1].Close(); secDB1.Close(); secDB2.Close(); db.Close(); }