I love LINQ . It gives the developers the power to query databases and lists in a manner far more succint, readable and elegant than that could otherwise be obtained via traditional looping methods ( you know, the combination kinds of for, if ) that normally result in lines and lines of code, methods and sub-methods calling. LINQ combines the succintness of SQL queries with the compile-time type checking advantage offered by C#, and produces code that is far more intuitive and readable than SQL or C# custom tailored filtering functions.
But after using it for quite sometime, I found that LINQ could be a bit prohibitive. Prohibitive in the sense that you always have to write LINQ expressions that are big, complicated, ugly and undecipherable at times.
Take a look at the below queries, see how much you can understand out of it?
public DateTime MyDateTime(IEnumerable<timedb.timerecordrow> relatedForm,
DateTime lastDateTime)
{
DateTime dt1 = relatedForm.OrderBy(record => record.EnterTime).FirstOrDefault(record =>
record.EnterTime > lastDateTime).
EnterTime;
DateTime dt2 = relatedForm
.Where(record => !record.IsLeaveTimeNull())
.OrderBy(record => record.LeaveTime)
.FirstOrDefault(record =>record.LeaveTime > lastDateTime).
LeaveTime;
if (dt1 >= dt2)
return dt2;
else
{
return dt1;
}
}
public List<actioninfo> PullLogRecord()
{
var descriptionDB = ActionDescriptionAdapter.GetData();
var timeDB = TimeRecordAdapter.GetData();
var groupByAction = timeDB.GroupBy(e => e.UserActionReference);
var groupByActionAndCurrElement = groupByAction.Select
(
group=>new {Key = descriptionDB
.Where(record=>record.UserAction==group.Key)
.Select(record=>record.Description).Single(),
NestedGroup= group.ToLookup
(
result=>result.CurrElement,
result=>new TimerInformation()
{
EnterTime = result.EnterTime,
LeaveTime = result.IsLeaveTimeNull() ?
MyDateTime(timeDB.ToList(), result.EnterTime) :
result.LeaveTime
}
)}
);
var dictionary = groupByActionAndCurrElement.ToDictionary
(
result => result.Key,
result => result.NestedGroup
);
List<actioninfo> actionInfos=new List<actioninfo>();
foreach (string key in dictionary.Keys)
{
ActionInfo ai = new ActionInfo(){ActionName = key};
foreach (var pair in dictionary[key])
{
ai.ElementInfo.Add(new ElementInfo()
{
ElementName = pair.Key,TimingInfo = pair.ToList()
});
}
actionInfos.Add(ai);
}
return actionInfos;
}
It's awfully long. But what it does is relatively simple:
- Pull records from a data table
- Group the data in terms of description and CurrElement tables.
- After the grouping, get each of the EnterTime and LeaveTime for each record and put them in a list, and put the list into an ElementInfo object, and so on. If the LeaveTime is a null, then it will find the first record that immediately after the corresponding EnterTime.
With such a long query, debugging it becomes very difficult. I have tried to break it into smaller methods, but so far only succeeded in spinning off one method. The whole query is still can't fit into a page. It's still a pain to read.
If I were to write my own C# code, although I might need more lines to do it, but at least I could write sub-functions to make things easier to understand. But with LINQ... that's the best I could produce, given my limited time and relatively low exposure in it.
Is there a way to improve on this?