One of the cool new features of Alchemy 8.2.2, aka SP4, is the ability to copy search results to another database. This is very similar to one of the problems I ask my Alchemy SDK students to solve during a group exercise. The goal of the exercise is to write a program that will do a search, and then copy all of the results to another database.
There are at least two ways of solving this problem. You could do a Item.Retrieve to save it out to a temp directory, then Item.CreateItem to add it to a new database. That's great, but it means that you have another location for the files you now have to clean up. What would be better is if you could stream the content from one database to another. Well, you can do that and that's what I am going to do right here.
The key is to use the Builder object. First BeginStreamData, then for each item do a BeginRecord, AppendData, then EndRecord. When everything is copied over, EndStreamData. When calling AppendData, the data is coming from the source item and you call GetContent.
Here is the full source code for a command line app that does the job:
1: using System;
2: using System.Collections.Generic;
3: using System.Text;
4:
5: namespace SearchToDB
6: { 7: class Program
8: { 9: static void Main(string[] args)
10: { 11: if (args.Length == 0)
12: return;
13: Alchemy.Application auApp = new Alchemy.Application();
14: auApp.LoadOptionsFile(""); 15:
16: Alchemy.Database destDB = auApp.Databases[1];
17: Alchemy.SearchGroup sg = auApp.SearchGroups.Add("MyNewSearchGroup"); 18:
19: foreach (Alchemy.Database db in auApp.Databases)
20: { 21: sg.Databases.Add(db.Path);
22: if (db.Title == "Search Results")
23: destDB = db;
24: }
25:
26: Alchemy.Query auQuery = auApp.NewQuery();
27: auQuery.AddFullTextQuery(args[0]);
28: auQuery.SearchGroup(sg);
29:
30: Alchemy.Builder build = auApp.NewBuilder(destDB);
31: build.BeginStreamData(null);
32: Alchemy.Item searchFolder = destDB.Root.CreateFolder(Alchemy.AuPosEnum.auPosLastChild);
33: searchFolder.Title = "Search for " + args[0] + " on " + DateTime.Now.ToString();
34:
35: foreach (Alchemy.Result result in auQuery.Results)
36: { 37: Alchemy.Item dbFolder = searchFolder.CreateFolder(Alchemy.AuPosEnum.auPosLastChild);
38: dbFolder.Title = result.Database.Title + " (" + DateTime.Now.ToShortTimeString() + ")"; 39: foreach (Alchemy.Item item in result.Items)
40: { 41: Alchemy.Item destItem = build.BeginRecord(dbFolder, Alchemy.AuPosEnum.auPosLastChild, "");
42: destItem.Title = item.Title;
43: build.AppendData(item.GetContent(0,item.Size,false),item.Size);
44: build.EndRecord(100);
45: }
46: }
47: build.EndStreamData();
48: }
49: }
50: }
In lines 17-24, I am creating a new SearchGroup, then going through all the databases in my profile.ini to add them to the search group and then seeing if it is my search results database. After that I do the search, create a builder object, and BeginStreamData. Before going through all of the items, I create a folder in the database that is named for the current search and date.
Since each result is a list of items within one database, I create a folder named for that database. Then I go to each item in the result, do a build.BeginRecord, passing it the database folder, and where I want to create the item in relation to that folder. I set the Title to be the same as the title of the source item. Then I call AppendData. But I have to get the content from somewhere. Luckily I can call item.GetContent. The first parameter is where I want to start from (byte 0), how big the file is (item.size), and whether I want the annotations. Then I tell it that I want to stop when it gets to 100 percent of the file. After all the files are copied over, I call EndStreamData and we are all done.
Its a pretty cool solution and could be useful if you aren't ready to upgrade to SP4. Enjoy!
Matt (Trainer Matts Blog / Technovangelist)