This code feels like it goes through too many conversions to accomplish my goal:
based on an IEnumerable of ids get those objects from a data store and set their
DisplayOrder
property to the position of the associated id.
Is there a more elegant solution that I'm missing?
public void ReorderElements(IEnumerable<int> elementSks)
{
var elementsToReorder = GetSession().QueryOver<DocumentElement>()
.WhereRestrictionOn(de => de.DocumentElementSk).IsIn(elementSks.ToArray()).List();
var elementOrder = elementSks.Select((sk, i) => new { Sk = sk, Order = i })
.ToDictionary(p => p.Sk, p => p.Order);
elementsToReorder.ToList()
.ForEach(e => e.DisplayOrder = elementOrder[e.DocumentElementSk]);
this.Save(elementsToReorder);
}
2 Answers 2
If the list on input is going to be short, or if performance doesn't matter to you, you can simplify the code by using IndexOf()
instead of the dictionary:
public void ReorderElements(IEnumerable<int> elementSks)
{
var elementsToReorder = GetSession().QueryOver<DocumentElement>()
.WhereRestrictionOn(de => de.DocumentElementSk).IsIn(elementSks.ToArray()).List();
var elementOrder = elementSks.ToList();
foreach(var element in elementsToReorder)
element.DisplayOrder = elementOrder.IndexOf(element.DocumentElementSk);
this.Save(elementsToReorder);
}
Please try this. I wrote this without testing or even compiling.
public void ReorderElements(IEnumerable<int> elementSks)
{
var skToElementsToReorder = GetSession().QueryOver<DocumentElement>()
.WhereRestrictionOn(de => de.DocumentElementSk).IsIn(elementSks.ToArray())
.ToDictionary(el => el.DocumentElementSk, el => el);
int index = 0;
foreach(int sk in elementSks)
{
// Assumes that the key exists - the .IsIn restriction right before helps
skToElementsToReorder[sk].DisplayOrder = index++;
}
this.Save(elementsToReorder);
}
Somehow I think that this can help: http://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b (as long as you can zip elementSks together with an index. Let me try a simpler version:
public class /* or struct ? */Element
{
public string name;
public in sk;
public int index;
}
// I am not fluent in LINQ, but Linq.Zip might help to generate these?
public class SkTuple
{
int sk;
int index;
}
// Now you have an `IEnumerable` of each somehow, and you want to do an update at the same time as you do a join ... like this?
https://stackoverflow.com/questions/709560/linq-in-line-property-update-during-join
This kind of got me thinking that maybe SQL is king after all - perhaps you want to just save this list of ids into a temp table where table id will be the index, and then call a stored procedure which will use a join and an update like here.
-
\$\begingroup\$ The linq to retrieve
elementsToReorder
is NHibernate's new QueryOver syntax. It's just a rehashing of their ICriteria expression syntax. It boils down to SQL and doesn't have that much affect on performance. Everything after the object retrieval is what I'm most worried about. \$\endgroup\$ahsteele– ahsteele2012年03月08日 03:43:28 +00:00Commented Mar 8, 2012 at 3:43
elementSks
. \$\endgroup\$