Domanda

Ho un elenco che assomiglia a:

Movie          Year
-----          ----
Fight Club     1999
The Matrix     1999
Pulp Fiction   1994

Utilizzando CAML e l'oggetto SPQuery ho bisogno di ottenere un elenco distinto di elementi dalla colonna Anno che popolerà un controllo a discesa.

Cercare in giro non sembra essere un modo per farlo all'interno della query CAML.Mi chiedo come hanno fatto le persone per raggiungere questo obiettivo?

È stato utile?

Soluzione

Un altro modo per farlo è utilizzare DataView.ToTable-Method: il suo primo parametro è quello che rende distinto l'elenco.

            SPList movies = SPContext.Current.Web.Lists["Movies"];
            SPQuery query = new SPQuery();
            query.Query = "<OrderBy><FieldRef Name='Year' /></OrderBy>";

            DataTable tempTbl = movies.GetItems(query).GetDataTable();
            DataView v = new DataView(tempTbl);
            String[] columns = {"Year"};
            DataTable tbl = v.ToTable(true, columns);

È quindi possibile procedere utilizzando il DataTable tbl.

Altri suggerimenti

Se si desidera associare i risultati distinti per un DataSource di per esempio un ripetitore e mantenere l'elemento reale tramite il metodo e.Item.DataItem gli eventi ItemDataBound, il modo in cui DataTable non è andare a lavorare. Invece, e poi anche quando non voler associarlo a un DataSource, si potrebbe anche usare LINQ per definire i valori distinti.

// Retrieve the list. NEVER use the Web.Lists["Movies"] option as in the other examples as this will enumerate every list in your SPWeb and may cause serious performance issues
var list = SPContext.Current.Web.Lists.TryGetList("Movies");

// Make sure the list was successfully retrieved
if(list == null) return;

// Retrieve all items in the list
var items = list.GetItems();

// Filter the items in the results to only retain distinct items in an 2D array
var distinctItems = (from SPListItem item in items select item["Year"]).Distinct().ToArray()

// Bind results to the repeater
Repeater.DataSource = distinctItems;
Repeater.DataBind();

Ricordate che poiché non v'è alcun supporto per le query CAML distinti, ogni campione fornite in questa pagina troverà tutti gli elementi dalla SPList. Questo può andare bene per le liste più piccole, ma per liste con migliaia di listitems, questo sarà seriamente essere un killer di prestazioni. Purtroppo non c'è modo per raggiungere lo stesso, non più ottimizzato.

Non c'è DISTINCT in CAML per popolare il menu a discesa provare a utilizzare qualcosa come:

foreach (SPListItem listItem in listItems)
    {
        if ( null == ddlYear.Items.FindByText(listItem["Year"].ToString()) )
       {
                   ListItem ThisItem = new ListItem();
                   ThisItem.Text = listItem["Year"].ToString();
                   ThisItem.Value = listItem["Year"].ToString();
                   ddlYear.Items.Add(ThisItem);
        }
   }

presuppone che il menu a discesa è chiamata ddlYear.

Si può passare dalla SPQuery a SPSiteDataQuery? Si dovrebbe essere in grado di, senza problemi.

Dopo di che, è possibile utilizzare il comportamento ado.net di serie:

SPSiteDataQuery query = new SPSiteDataQuery();
/// ... populate your query here. Make sure you add Year to the ViewFields.

DataTable table = SPContext.Current.Web.GetSiteData(query);

//create a new dataview for our table
DataView view = new DataView(table);

//and finally create a new datatable with unique values on the columns specified

DataTable tableUnique = view.ToTable(true, "Year");

Dopo imbattersi incarico dopo post su come questo era impossibile, ho finalmente trovato un modo. Questo è stato testato in SharePoint Online. Ecco una funzione che ti porterà tutti i valori univoci per una colonna. E 'solo richiede di passare in Id lista, Vista Id, nome della lista interna, e una funzione di callback.

function getUniqueColumnValues(listid, viewid, column,  _callback){
var uniqueVals = [];
$.ajax({
    url: _spPageContextInfo.webAbsoluteUrl + "/_layouts/15/filter.aspx?ListId={" + listid + "}&FieldInternalName=" + column + "&ViewId={" + viewid + "}&FilterOnly=1&Filter=1",
    method: "GET",
    headers: { "Accept": "application/json; odata=verbose" }
    }).then(function(response) {
        $(response).find('OPTION').each(function(a,b){
            if ($(b)[0].value) {
                uniqueVals.push($(b)[0].value);
            }
        });
        _callback(true,uniqueVals);
},function(){
    _callback(false,"Error retrieving unique column values");
});

}

Stavo considerando questo problema prima di oggi, e la soluzione migliore che potevo pensare utilizza il seguente algoritmo (mi dispiace, nessun codice al momento):

L is a list of known values (starts populated with the static Choice options when querying fill-in options, for example)
X is approximately the number of possible options

1. Create a query that excludes the items in L
1. Use the query to fetch X items from list (ordered as randomly as possible)
2. Add unique items to L
3. Repeat 1 - 3 until number of fetched items < X

Ciò ridurrebbe il numero totale di elementi restituiti in modo significativo, a costo di fare più query.

Non si fa molto importa se X è del tutto esatto, ma la casualità è molto importante. In sostanza la prima query è probabile che includono le opzioni più comuni, quindi la seconda query escludere questi ed è probabile che includono le opzioni più comuni prossimi e così via attraverso le iterazioni.

Nel migliore dei casi, la prima query include tutte le opzioni, poi la seconda query sarà vuoto. (Articoli X recuperati in totale, più di 2 domande)

Nel peggiore dei casi (ad esempio, la query è ordinato dalle opzioni che stiamo cercando, e ci sono più di X articoli con ogni opzione) faremo tante domande quante sono le opzioni. Tornando circa X * X elementi in totale.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top