views:

226

answers:

3

Hi,

I'm looking for a way to add a text file to a SharePoint list that DOESN'T enumerate the entire file set. According to this SharePoint best practices article, you shouldn't access the SPList.Files property because it enumerates the entire collection. Unless you actually want every item, then it's very inefficient. All I want to do is add a single text file to the root folder of a SharePoint list. So far I'm using the following:

using (MemoryStream stream = new MemoryStream())
   {
       StreamWriter writer = new StreamWriter(stream, Encoding.UTF8);

       // write some stuff to the stream ...
       // create a file-name-safe URL ...
       // create a SPFileCollectionAddParameters object ...   

       // add the file
       SPFile newFile = loggingList.RootFolder.Files.Add(fileURL, stream, addProperties);  

}

So, is enumerating SPList.RootFolder.Files the same as SPList.Files, in this case (since there is only a root folder with text files) and if so, is there a way to add a single file without enumerating the file collection?

Thanks in advance. :D

+1  A: 

Actually there's nothing wrong with calling Files.Add. Simply accessing the member will not enumerate the collection. If you were to call GetEnumerator() on it or use it in a foreach loop, that would trigger the enumeration.

Josh Einstein
Cheers mate but The MSDN article says otherwise. I also read an article by someone who had used a dll reflector to look at the code behind a another similar SharePoint object property... it used an unbounded CAML query which queried and returned every single item, EVERY time you accessed the property. :\. Could be wrong though.
I just checked Reflector. Indeed it creates a new SPFileCollection each time the property is accessed but it does not start enumerating it. The same is true of SPList.Items.
Josh Einstein
Sweet. :D .So the new collection is empty? I guess it doesn't start enumerating until you actually try to access elements of the list. I.e. the collection's iterator actually performs database access stuff and the collection has methods to push new items back to the content DB after you add to the collection and call update.... Thanks. I thin k that answers it. :D
Technically it's not empty but more like Schroedinger's cat. :) Once you "observe" it, it fills the collection. There is a table on that MSDN article you linked that shows which members trigger a collection load.
Josh Einstein
Cheers Josh. Einstein indeed! ;D
Just out of interest; which reflector tool do you use? I'm just about to give Red Gate's .NET reflector a go, but if you had any alternate/better recommendations, that'd be appreciated. :D
I use Red Gate reflector. I've been using it since it was Lutz Roeder's baby. I like it because I can drop it in a folder that I keep sync'd with Live Mesh and it's always up-to-date on all the machines I use.
Josh Einstein
A: 

Being afraid to use SPList.Items (similar to SPList.Files, but used in simple lists, not document libraries), we created a helper function that returns an empty collection, hence NOT fetching all items from the server:

public static SPListItemCollection CreateEmptyCollection(SPList List)
 {
   const string EmptyQuery = "0";
   SPQuery q = new SPQuery {Query = EmptyQuery};
   return List.GetItems(q);
 }

Then, when adding items to a list, we do it like this:

ListItem = CreateEmptyCollection(someList).Add("/sites/somesite/lists/somelist/path/to/required/folder", SPFileSystemObjectType.File, "");
naivists
Aha... I knew I'd seen this somewhere! I once found and article that suggested the same thing, but made it an SPList extension method. I'll add a post. Cheers dude.
A: 

Thanks naivists. You have reminded that I once saw an article that suggested the same thing but as an extension method on SPList:

public static SPListItem AddItemOptimized(this SPList list, string folderUrl, 
        SPFileSystemObjectType underlyingObjectType, string leafName)
    {
        const string EmptyQuery = "0";
        SPQuery q = new SPQuery
        {
            Query = EmptyQuery
        };
        return list.GetItems(q).Add(folderUrl, underlyingObjectType,leafName);
    }