Outlook-Addin: How to retrive folder tree fast when Exchange-Online is used - outlook-addin

I'm using Outlook Redemption library.
I am trying to retrieve the folder list of an Outlook store. I only need folders which meet a some criterias and only need their name and there DefaultMessageClass.
Iteration the RDOFolder objects is quite slow when an Exchange Account without a cached is used.
So I played around with the GetAllChildFolders() and combined it the the RODFolderItems findmethod.
http://www.dimastr.com/redemption/RDOFolders.htm
var allFolder = ((RDOFolder2)rootFolder).GetAllChildFolders();
string folderSelect = "SELECT Name, EntryId, DefaultMessageClass FROM FOLDER WHERE \"http://schemas.microsoft.com/mapi/proptag/0x3613001F\" like '%Note%'";
try
{
RDOFolder vFolder = vFolders.Find(folderSelect);
while (vFolder != null)
{
System.Diagnostics.Debug.WriteLine(vFolder.Name);
System.Diagnostics.Debug.WriteLine(vFolder.EntryID);
System.Diagnostics.Debug.WriteLine(vFolder.DefaultMessageClass);
vFolder = vFolders.FindNext();
}
}
catch (Exception ex)
{
//log error here!
}
Now I got two questions!
1. SQL Syntax
From the docmentation of find method
The properties specified in the SQL query must either use the Outlook Object Model (or RDO)
property name (e.g. Subject, Email1Address)
I can't make Outlook or Redemption properties work within the SQL statement. Has somebody a working example?
2. Performance access properties
The online documentation states the following.
Including the SELECT clause allows Redemption to pre-fetch the
properties from the folder hierarchy table without opening the item
resulting in a significant performance gain (see example "I wish there was one :-)"). If you
later access a property not specified in the SELECT clause, Redemption
will open the item.
How do I access the properties prefetch from the folder hierarchy?
If I use RDOFolder.Name, the whole folder object is opened and there is not much of an performance gain.

Which properties do not work? Are you getting a particular error?
What is your full SELECT statement? To avoid the chance of opening a folder, use RDOFolders.MAPITable.ExecSQL - it will
return an ADODB.Recordset object.

Related

Related entities not loading when using Include with Linq to Entities

In my schema, I have the following relevant entities:
Basic schema for Element/Folder/User/Role
I'm trying to load a list of the Folders that each User has access to - either directly or by virtue of the User having a Role that has access to the Folder. I've split the requirement into two pieces (direct and indirect) and used a Union to pull the records back in a single collection, with only one call to the database.
I've got the L2E statement below running - as long as a User has a (direct or indirect) record in Access, the Folder entity will be returned in the list (Note: sUserElmKey is the key of the current User).
Dim fldList = (From fld As Folder In ctxClient.Elements.OfType(Of Folder)() _
Join acs As Access In ctxClient.Accesses
On acs.ElementKey Equals fld.ElementKey
Where acs.UserRoleElementKey = sUserElmKey _
Select fld
).Union _
(From fld As Folder In ctxClient.Elements.OfType(Of Folder)() _
Join acs As Access In ctxClient.Accesses
On acs.ElementKey Equals fld.ElementKey
Join rol As Role In ctxClient.Elements.OfType(Of Role)()
On rol.ElementKey Equals acs.UserRoleElementKey
Where (From usr As User In rol.Users
Where usr.ElementKey = sUserElmKey).Any _
Select fld
)
This worked fine when I just needed to know if any access to each Folder was available to the User. Now I need to define other logic based on which AccessTypeCode the User has for each Folder.
Given that I need to iterate over the resulting entities in the collection in order to load a different collection of objects that represents nodes in the tree UI, I figured I'd just add an Include("Accesses") to each sub-statement above. As I iterated through the resulting collection, I could write the logic to set the needed flags for each of the new node objects (e.g. if the User has AccessTypeCode "VIEW", then they have read-only access; "OWN" or "NEW" and they have read/write access).
Unfortunately, I haven't been able to find where to add the Include to do this properly - I've put it after the "ctxClient.Elements" as well as after the ".OfType(Of Folder()", but while the code compiles and runs, the debugger shows 0 records for the Accesses collection under each Folder when I'm iterating.
Rewriting this as a lambda expression is an option, but I think I might just find myself in the same place.
Any ideas on how to resolve this?
Looking at you schema I think you can rewrite the query as follows:
(From fld In ctxClient.Elements.OfType(Of Folder)()
Where fld.Accesses.Any(Function(acs) acs.UserRoleElementKey = sUserElmKey)
Select fld)
.Union
(From fld In ctxClient.Elements.OfType(Of Folder)()
Where fld.Accesses.Any(Function(acs) acs.UserRoleElement.Users
.Any(Function(usr) usr.ElementKey = sUserElmKey))
Select fld)
This checks whether there is any access, directly or through roles, without having to Include accesses.

Checking if certain key exists in database

I have saved certain MDX query and I run them using ADOMD.NET. I get CellSet back which I convert into dataset. All this is working fine. Now the DB team has changed the cube structure. They have updated the DimesnionName, Attribute Name etc. Some dimensions got renamed and some got deleted. Becuase of this I am unable to run my saved queries. I want to create a console application, which will take list of keys ([DimensionName].[AttributeName] or [DimensionName].[AttributeName].[MemeberName] format) and it will tell me following keys does not exists.
Please let me know if this is possible programatically. I dont want to check it manually.
Kindly share a link or code which will help me acheive this.
Thank you.
If you're using ADOMD already this should be no problem, just use the metadata queries:
http://msdn.microsoft.com/en-us/library/ms123485.aspx
Alternatively, AMO is nice http://msdn.microsoft.com/en-us/library/microsoft.analysisservices.aspx
I use it in SSIS for processing, you could easily use it in .Net to test existence of elements:
using Microsoft.AnalysisServices;
...
Server server = new Server();
server.Connect(cubeConnectionString);
Database database = server.Databases.FindByName(databaseName);
Cube cube = database.Cubes.FindByName(cubeName);
foreach (MeasureGroup measureGroup in cube.MeasureGroups)
{
foreach (Partition partition in measureGroup.Partitions)
{
...
}
}
foreach (CubeDimension cubeDimension in cube.Dimensions)
{
Dimension dimension = cubeDimension.Dimension;
var dimName = dimension.Name;
...
}
Finding the names in advance for all the elements you need is probably the hard part (And keeping it all up-to-date).
Would it not be easier to fire all the queries at the cube and try to trap the "no such thing" response?

Native Query Mapping on the fly openJPA

I am wondering if it is possible to map a named native query on the fly instead of getting back a list of Object[] and then looping through and setting up the object that way. I have a call which I know ill return a massive data set and I want to be able to map it right to my entity. Can I do that or will I have to continue looping through the result set.
Here is what I am doing now...
List<Provider> ObjList = (List<Provider>) emf.createNativeQuery(assembleQuery(organizationIDs, 5)).getResultList();
That is my entity, the List (my entity is the provider). Normally I would just return a List<Object[]>
and then I would loop through that to get back all the objects and set them up as new providers and add them to a list....
//List<Provider> provList = new ArrayList<Provider>();
/*for(Object[] obj: ObjList)
{
provList.add(this.GetProviderFromObj(obj));
}*/
As you can see I commented that section of the code out to try this out. I know you can map named native queries if you put your native query in the entity itself and then call it via createNamedQuery. I would do it that way, but I need to use the IN oracle keyword because I have a list of ID's that I want to check against. It is not just one that is needed. And as we all know, native queruies don't handle the in keyword to well. Any advice?
Sigh, If only the IN keyword was supported well for NamedNativeQueries.
Assuming that Provider is configured as a JPA entity, you should be able to specify the class as the second parameter to your createNativeQuery call. For example:
List<Provider> ObjList = (List<Provider>) emf.createNativeQuery(assembleQuery(organizationIDs, 5), Provider.class).getResultList();
According to the documentation, "At a minimum, your SQL must select the class' primary key columns, discriminator column (if mapped), and version column (also if mapped)."
See the OpenJPA documentation for more details.

Check if property exists in RavenDB

I want to add property to existing document (using clues form http://ravendb.net/docs/client-api/partial-document-updates). But before adding want to check if that property already exists in my database.
Is any "special,proper ravendB way" to achieve that?
Or just load document and check if this property is null or not?
You can do this using a set based database update. You carry it out using JavaScript, which fortunately is similar enough to C# to make it a pretty painless process for anybody. Here's an example of an update I just ran.
Note: You have to be very careful doing this because errors in your script may have undesired results. For example, in my code CustomId contains something like '1234-1'. In my first iteration of writing the script, I had:
product.Order = parseInt(product.CustomId.split('-'));
Notice I forgot the indexer after split. The result? An error, right? Nope. Order had the value of 12341! It is supposed to be 1. So be careful and be sure to test it thoroughly.
Example:
Job has a Products property (a collection) and I'm adding the new Order property to existing Products.
ravenSession.Advanced.DocumentStore.DatabaseCommands.UpdateByIndex(
"Raven/DocumentsByEntityName",
new IndexQuery { Query = "Tag:Jobs" },
new ScriptedPatchRequest { Script =
#"
this.Products.Map(function(product) {
if(product.Order == undefined)
{
product.Order = parseInt(product.CustomId.split('-')[1]);
}
return product;
});"
}
);
I referenced these pages to build it:
set based ops
partial document updates (in particular the Map section)

Tridion 2011 - Engine.GetObject overloads

I found the following difference between the old VBScript API and the .Net API:
In the old VBScript API it's possible to invoke "TDSE.getObject" to retrieve a Tridion object passing by the webdav path, an integer to select how to open it (read only, read and write, etc) and the ID of the publication where there is the exact element of the blueprint we want.
In the new .Net API all I found was "Engine.GetObject" but it only receives the TCM ID or the webdav path of an element.
Our scenario is the following; in the old VBScript code, this overload of the getObject method was used to avoid some permission issues detected while using TCM IDs instead of the webdav paths and because it's much more handful when you need to copy the code between different environments (see DEV, PREPROD and PROD for example), avoiding changing TCM IDs.
So my questions are:
Is there and overload like the old one in the new .Net API?
If not, is there a way of retrieving items by webdav keeping in mind that some of them could be localized and changed from their parent? (the old way works with this, if you send the root webdav path it will retrieve local objects even if their names aren't exactly the same as the parents)
Thank you!
Do you want to be able to use the webdav url of the top-level item, and specify the publication id from which to get the item?
I would create an extension method on Engine that does this for you:
public static T GetObject<T>(this Engine engine, string webDavUrl, int publicationId)
where T : IdentifiableObject
{
[logic to retreive the item and then if needed
get the correct tcm uri and get the intended item]
return item as T;
}
However, this is quite an expensive operation since you get two objects instead of one. So I dont know if I would use this method very often.
Here some samples
IdentifiableObject item = engine.GetObject(new TcmUri("tcm:5-677"));
//will give you the latest approved version in the publication 5.
IdentifiableObject item = engine.GetObject(new TcmUri("tcm:5-677-v0"));
//will give you the WF or Editable version.
TcmUri uri = new TcmUri("tcm:5-677");
uri.PublicationId = 6;
IdentifiableObject item = engine.GetObject(uri);
//will give you the latest approved version in the publication 6.
Engine.GetObject has 4 overloaded method.
GetObject(Session, string)
GetObject(string)
GetObject(TcmUri)
GetObject(Item)
You can check the Tom.Net Api for more details.
Actually, using Engine.GetObject Method (String) should work.
public virtual IdentifiableObject GetObject(
string itemUriOrWebDavUrl
)
You can do something in this way:-
Get the Object based on WebDav URL
Get the TCM ID from this object
Based on your publication, modified your TCM ID accordingly and do your stuff
OR
Try something this way too:-
Repository testRepository = (Repository)session.GetObject("tcm:0-2-1");
Component testComponent = (Component)testRepository.GetObject(webdavURL); //Assuming actual TCM ID is "tcm:1-3"
Console.WriteLine(testComponent.Id); // should show "tcm:2-3"
// Do Your Other Stuff