I'm sure this has been answered before, but can't seem to find it.
I'm looking for a simple download (or tutorial) for building an IQueryable that can be sorted, paged and searched.
e.g.
IQueryable<T> myThings , params[] searchKeyValuePairs, params[] orderKeyValuePairs, int pageSize, int pageNumber
Or something similar. Guessing it will be using Dynamic Linq.
My requirement is for a number of MVC3 views for broadly similar data. BA specified about 20 views of each of 10 data types...but MOST of these views are simply "All Today" and "Sorted by Cost" type views.
Data is from SQL or Oracle through EF4.
For paging:
public class PagingList<T> : List<T>
{
public int PageIndex { get; set; }
public int PageSize { get; set; }
public int TotalCount { get; set; }
public int TotalPages { get; set; }
public string pagerange { get; set; }
public int pagingrange { get; set; }
public PagingList(IQueryable<T> data, int page, int pagesize)
{
PageIndex = page;
PageSize = pagesize;
TotalCount = data.Count();
TotalPages = (int)Math.Ceiling(TotalCount /(double)PageSize);
this.AddRange(data.Skip(PageIndex * PageSize).Take(PageSize));
}
//public void GeneratePageRange()
//{
// for (int i = 1; i <= TotalPages; i++)
// {
// pagingrange = i
// }
//}
public bool HasPreviousPage
{
get { return (PageIndex > 0); }
}
public bool HasNextPage
{
get { return (PageIndex + 1 < TotalPages); }
}
}
For searching:
public static class DataYouWant
{
/// <summary>
/// Function which returns the Griddata for json result of jqGrid
/// </summary>
public static GridData Getdata<T>(ObjectSet<T> baseList,int currentPage,int rowsPerPage,
string sortcolumn,
string sortord,
string searchQuery,
string searchColumns)where T: class
{
var query = baseList.OrderBy("it." + sortcolumn + " " + sortord);
string strPredicate = string.Empty;
dynamic searchvalue = searchQuery;
if (!string.IsNullOrEmpty(searchColumns))
{
var coltype = baseList.EntitySet.ElementType.Members[searchColumns].TypeUsage.EdmType;
if (CheckIntType(coltype))
{
strPredicate = "it." + searchColumns + " = #" + searchColumns;
searchvalue = Convert.ToInt32(searchQuery);
}
else
strPredicate = "CONTAINS(it." + searchColumns + ",#" + searchColumns + ")";
query = baseList.Where(strPredicate, new ObjectParameter(searchColumns, searchvalue)).OrderBy("it." + sortcolumn + " " + sortord);
}
var pageddata = new PagingList<T>(query, currentPage, rowsPerPage);
return new GridData()
{
Page = pageddata.PageIndex + 1,
Records = pageddata.TotalCount,
Rows = pageddata,
Total = pageddata.TotalPages,
UserData = "ok"
};
}
/// <summary>
/// Checks the EdmType and
/// </summary>
public static bool CheckIntType(EdmType objEdmType)
{
switch (objEdmType.Name)
{
case "Int32":
return true;break;
case "Int16":
return true;break;
case "Int64":
return true; break;
case "Decimal":
return true;break;
default:
return false;
break;
}
}
}
Related
Is there a way to implement Generic filter for NHibernate on a repository layer? As per Microsoft API Guidelines, the sort and filters are passed as string API Guidelines. what will be the approach to that using NHibernate to make it generic?
Please have a look at this post.There is a section Paging with NHibernate.
The code snippet below is from this post.
The approach is to implement a class (in the post it was PagedResult<T>) in your case FilteredResult<T>. Having this class you can implementan extension (in post was NHibernatePagedResultExtensions) in this case NHibernateFilteredResultExtensions.
And the last thing left is to apply this extansion exacly the same way.
Hope this will help.
public abstract class PagedResultBase
{
public int CurrentPage { get; set; }
public int PageCount { get; set; }
public int PageSize { get; set; }
public int RowCount { get; set; }
public string LinkTemplate { get; set; }
public int FirstRowOnPage
{
get { return (CurrentPage - 1) * PageSize + 1; }
}
public int LastRowOnPage
{
get { return Math.Min(CurrentPage * PageSize, RowCount); }
}
}
public class PagedResult<T> : PagedResultBase
{
public IList<T> Results { get; set; }
public PagedResult()
{
Results = new List<T>();
}
}
public static class NHibernatePagedResultExtensions
{
public static async Task<PagedResult<T>> GetPagedAsync<T>(this IQueryable<T> query, int page, int pageSize)
{
var result = new PagedResult<T>
{
CurrentPage = page,
PageSize = pageSize,
RowCount = query.Count()
};
var pageCount = (double)result.RowCount / pageSize;
result.PageCount = (int)Math.Ceiling(pageCount);
var skip = (page - 1) * pageSize;
result.Results = await query.Skip(skip).Take(pageSize).ToListAsync();
return result;
}
}
public async Task<IActionResult> Index(int page = 1)
{
var result = await _session.RunInTransaction(async () =>
{
var books = await _session.Books
.Where(b => b.Title.StartsWith("How to"))
.GetPagedAsync(page, pageSize: 25);
return _mapper.Map<PagedResult<BookModel>>(books);
});
return View(result);
}
I have a SQlite based Xamarin Forms application on my Android Phone and Wear device. Syncing between my Phone and my Wear watch is performed according to my answer to another Question.
My database has the folowing tables Match and MatchStat:
public class Match
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public DateTime MatchDate { get; set; }
public TimeSpan MatchTime { get; set; }
public string Home { get; set; }
public string Guest { get; set; }
public int HomeScore { get; set; }
public int GuestScore { get; set; }
public bool Active { get; set; }
public bool Done { get; set; }
public string HomeColor { get; set; }
public string GuestColor { get; set; }
public Match()
{ }
}
public class MatchStat
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public int MatchId { get; set; }
public int ActionMin { get; set; }
public int HomeScore { get; set; }
public int GuestScore { get; set; }
public string ActionItem { get; set; }
public string PlayerName { get; set; }
public MatchStat()
{ }
}
If I want to sync my Match and all the MatchStat data from one device to the other I am doing it by mapping the data as strings in my MainActivity:
public async static void SendNewMatch(Match match, string path)
{
if (!client.IsConnected)
client.Connect();
await Task.Delay(200);
try
{
var request = PutDataMapRequest.Create(path);
var map = request.DataMap;
if (match != null)
{
map.PutString("Device", device);
map.PutString("Item", "AddMatch");
map.PutString("Home", match.Home);
map.PutString("Guest", match.Guest);
map.PutString("Active", match.Active.ToString());
map.PutString("Done", match.Done.ToString());
map.PutString("GuestScore", match.GuestScore.ToString());
map.PutString("HomeScore", match.HomeScore.ToString());
map.PutString("Date", match.MatchDate.Date.ToString());
map.PutString("Time", match.MatchTime.ToString());
map.PutLong("UpdatedAt", DateTime.UtcNow.Ticks);
await WearableClass.DataApi.PutDataItem(client, request.AsPutDataRequest());
}
request.UnregisterFromRuntime();
}
catch
{ }
finally
{
client.Disconnect();
}
}
public async static void SendMatchStat(MatchStat matchstat, Match match, int matchstatsize, string path)
{
if (!client.IsConnected)
client.Connect();
await Task.Delay(200);
try
{
var request = PutDataMapRequest.Create(path);
var map = request.DataMap;
MatchHelper mh = new MatchHelper();
if (matchstat != null)
{
map.PutString("Device", device);
map.PutString("Item", "MatchStat");
map.PutString("Home", match.Home);
map.PutString("Date", match.MatchDate.Date.ToString());
map.PutString("Time", match.MatchTime.ToString());
map.PutString("ActionItem", matchstat.ActionItem);
map.PutString("ActionMin", matchstat.ActionMin.ToString());
map.PutString("GuestScore", matchstat.GuestScore.ToString());
map.PutString("HomeScore", matchstat.HomeScore.ToString());
map.PutString("MatchStatSize", matchstatsize.ToString());
//map.PutString("PlayerName", matchstat.PlayerName.ToString());
map.PutLong("UpdatedAt", DateTime.UtcNow.Ticks);
await WearableClass.DataApi.PutDataItem(client, request.AsPutDataRequest());
}
request.UnregisterFromRuntime();
}
catch
{ }
finally
{
client.Disconnect();
}
}
public void ProcessMessage(Intent intent)
{
if (intent.GetStringExtra("Device") != device)
{
switch (intent.GetStringExtra("Item"))
{
case "AddMatch":
{
AddMatch(intent);
break;
}
case "MatchStat":
{
InsertMatchStat(intent);
break;
}
}
}
}
private void AddMatch(Intent intent)
{
MatchHelper mh = new MatchHelper();
if (bool.Parse(intent.GetStringExtra("Active")))
{
ObservableCollection<Match> activeMatches = mh.GetActiveMatches();
foreach (Match activeMatch in activeMatches)
{
mh.InactivateMatch(activeMatch);
}
}
Match newmatch = new Match();
newmatch.Home = intent.GetStringExtra("Home");
newmatch.Guest = intent.GetStringExtra("Guest");
newmatch.HomeColor = intent.GetStringExtra("HomeColor");
newmatch.GuestColor = intent.GetStringExtra("GuestColor");
newmatch.Active = bool.Parse(intent.GetStringExtra("Active"));
newmatch.Done = bool.Parse(intent.GetStringExtra("Done"));
newmatch.HomeScore = int.Parse(intent.GetStringExtra("HomeScore"));
newmatch.GuestScore = int.Parse(intent.GetStringExtra("GuestScore"));
newmatch.Active = bool.Parse(intent.GetStringExtra("Active"));
newmatch.Done = bool.Parse(intent.GetStringExtra("Done"));
newmatch.MatchDate = DateTime.Parse(intent.GetStringExtra("Date"));
newmatch.MatchTime = TimeSpan.Parse(intent.GetStringExtra("Time"));
mh.InsertMatch(newmatch);
}
private void InsertMatchStat(Intent intent)
{
MatchHelper mh = new MatchHelper();
Match match = mh.GetSpecificMatch(intent.GetStringExtra("Home"), DateTime.Parse(intent.GetStringExtra("Date")), TimeSpan.Parse(intent.GetStringExtra("Time")));
if (match != null)
{
MatchStat machstat = new MatchStat();
machstat.MatchId = match.Id;
machstat.ActionItem = intent.GetStringExtra("ActionItem");
machstat.ActionMin = int.Parse(intent.GetStringExtra("ActionMin"));
machstat.GuestScore = int.Parse(intent.GetStringExtra("GuestScore"));
machstat.HomeScore = int.Parse(intent.GetStringExtra("HomeScore"));
machstat.PlayerName = intent.GetStringExtra("PlayerName");
mh.InsertMatchStat(machstat);
}
}
In my WearService I have my OnDataChanged:
public override void OnDataChanged(DataEventBuffer dataEvents)
{
var dataEvent = Enumerable.Range(0, dataEvents.Count)
.Select(i => dataEvents.Get(i).JavaCast<IDataEvent>())
.FirstOrDefault(x => x.Type == DataEvent.TypeChanged && x.DataItem.Uri.Path.Equals(_syncPath));
if (dataEvent == null)
return;
//get data from wearable
var dataMapItem = DataMapItem.FromDataItem(dataEvent.DataItem);
var map = dataMapItem.DataMap;
Intent intent = new Intent();
intent.SetAction(Intent.ActionSend);
intent.PutExtra("Device", map.GetString("Device"));
intent.PutExtra("Item", map.GetString("Item"));
switch (map.GetString("Item"))
{
case "AddMatch":
{
intent.PutExtra("Home", map.GetString("Home"));
intent.PutExtra("Guest", map.GetString("Guest"));
intent.PutExtra("HomeColor", map.GetString("HomeColor"));
intent.PutExtra("GuestColor", map.GetString("GuestColor"));
intent.PutExtra("Active", map.GetString("Active"));
intent.PutExtra("Done", map.GetString("Done"));
intent.PutExtra("HomeScore", map.GetString("HomeScore"));
intent.PutExtra("GuestScore", map.GetString("GuestScore"));
intent.PutExtra("Date", map.GetString("Date"));
intent.PutExtra("Time", map.GetString("Time"));
LocalBroadcastManager.GetInstance(this).SendBroadcast(intent);
break;
}
case "MatchStat":
{
intent.PutExtra("Home", map.GetString("Home"));
intent.PutExtra("Date", map.GetString("Date"));
intent.PutExtra("Time", map.GetString("Time"));
intent.PutExtra("ActionItem", map.GetString("ActionItem"));
intent.PutExtra("ActionMin", map.GetString("ActionMin"));
intent.PutExtra("GuestScore", map.GetString("GuestScore"));
intent.PutExtra("HomeScore", map.GetString("HomeScore"));
intent.PutExtra("PlayerName", map.GetString("PlayerName"));
LocalBroadcastManager.GetInstance(this).SendBroadcast(intent);
break;
}
}
}
Instead of sending the data via separate strings I want to send my Match data as database file (if necessary as .ToString). Is it possible to achieve this and how can I thereafter retrieve the data.
Second of all I have my MatchStats as a list (IEnumerable or ObservableCollection). Is it possible to send this as a list or do I have to send each MatchStat seperately. By sending the Matchstats seperately my other device will not receive them in the desired order and not all MatchStats are received.
Instead of sending database data as database file I now solved this by sending the Matchstats in one file instead of sending all seperate data.
public async static void SendMatchStats(ObservableCollection<MatchStat> matchstats, Match match, int matchstatsize, string path)
{
if (!client.IsConnected)
client.Connect();
await Task.Delay(80);
try
{
var request = PutDataMapRequest.Create(path);
var map = request.DataMap;
MatchHelper mh = new MatchHelper();
int cnt = 1;
if (matchstatsize != 0)
{
map.PutString("Device", device);
map.PutString("Item", "MatchStats");
map.PutString("Home", match.Home);
map.PutString("Date", match.MatchDate.Date.ToString());
map.PutString("Time", match.MatchTime.ToString());
map.PutString("MatchStatSize", matchstatsize.ToString());
map.PutString("Path", path);
foreach (MatchStat matchstat in matchstats)
{
map.PutString("ActionItem" + cnt.ToString(), matchstat.ActionItem);
map.PutString("ActionMin" + cnt.ToString(), matchstat.ActionMin.ToString());
map.PutString("Color" + cnt.ToString(), matchstat.Color);
//map.PutString("ColorSchemeId", matchstat.ColorSchemeId.ToString());
map.PutString("GuestScore" + cnt.ToString(), matchstat.GuestScore.ToString());
map.PutString("HomeScore" + cnt.ToString(), matchstat.HomeScore.ToString());
if (matchstat.PlayerName == null)
map.PutString("PlayerName" + cnt.ToString(), "");
else
map.PutString("PlayerName" + cnt.ToString(), matchstat.PlayerName.ToString());
cnt++;
}
map.PutLong("UpdatedAt", DateTime.UtcNow.Ticks);
await WearableClass.DataApi.PutDataItem(client, request.AsPutDataRequest());
}
request.SetUrgent();
request.UnregisterFromRuntime();
}
catch
{ }
finally
{
client.Disconnect();
}
}
In my WearService I have my OnDataChanged:
case "MatchStats":
{
int size = int.Parse(map.GetString("MatchStatSize"));
intent.PutExtra("Home", map.GetString("Home"));
intent.PutExtra("Date", map.GetString("Date"));
intent.PutExtra("Time", map.GetString("Time"));
intent.PutExtra("MatchStatSize", map.GetString("MatchStatSize"));
intent.PutExtra("Path", map.GetString("Path"));
for (int cnt = 1; cnt <= size; cnt++)
{
intent.PutExtra("ActionItem" + cnt.ToString(), map.GetString("ActionItem" + cnt.ToString()));
intent.PutExtra("ActionMin" + cnt.ToString(), map.GetString("ActionMin" + cnt.ToString()));
intent.PutExtra("Color" + cnt.ToString(), map.GetString("Color" + cnt.ToString()));
intent.PutExtra("GuestScore" + cnt.ToString(), map.GetString("GuestScore" + cnt.ToString()));
intent.PutExtra("HomeScore" + cnt.ToString(), map.GetString("HomeScore" + cnt.ToString()));
intent.PutExtra("PlayerName" + cnt.ToString(), map.GetString("PlayerName" + cnt.ToString()));
Console.WriteLine("PutExtra " + map.GetString("ActionMin" + cnt.ToString()) + " min " + map.GetString("HomeScore" + cnt.ToString()) + "-" + map.GetString("GuestScore" + cnt.ToString()));
Console.WriteLine("GetStringExtra " + intent.GetStringExtra("ActionMin" + cnt.ToString()) + " min " + intent.GetStringExtra("HomeScore" + cnt.ToString()) + "-" + intent.GetStringExtra("GuestScore" + cnt.ToString()));
}
LocalBroadcastManager.GetInstance(this).SendBroadcast(intent);
break;
}
And in MainActivity I am processing the data in a seperate void InsertMatchstats:
private void InsertMatchStats(Intent intent)
{
MatchHelper mh = new MatchHelper();
Match match = mh.GetSpecificMatch(intent.GetStringExtra("Home"), DateTime.Parse(intent.GetStringExtra("Date")), TimeSpan.Parse(intent.GetStringExtra("Time")));
int size = int.Parse(intent.GetStringExtra("MatchStatSize"));
if (match != null)
{
for (int cnt = 1; cnt <= size; cnt++)
{
MatchStat matchstat = new MatchStat
{
MatchId = match.Id,
ActionItem = intent.GetStringExtra("ActionItem" + cnt.ToString()),
ActionMin = int.Parse(intent.GetStringExtra("ActionMin" + cnt.ToString())),
Color = intent.GetStringExtra("Color" + cnt.ToString()),
//ColorSchemeId = int.Parse(intent.GetStringExtra("ColorSchemeId"));
GuestScore = int.Parse(intent.GetStringExtra("GuestScore" + cnt.ToString())),
HomeScore = int.Parse(intent.GetStringExtra("HomeScore" + cnt.ToString())),
PlayerName = intent.GetStringExtra("PlayerName" + cnt.ToString()),
Sync = true
};
if (matchstat.Color == null)
matchstat.Color = "#FFFFFF";
MatchStat checkMatchStat = mh.CheckMatchStat(matchstat.HomeScore, matchstat.GuestScore, matchstat.ActionItem, matchstat.MatchId);
if (checkMatchStat == null)
mh.InsertMatchStat(matchstat);
else
{
checkMatchStat.ActionMin = matchstat.ActionMin;
checkMatchStat.Color = matchstat.Color;
//checkMatchStat.ColorSchemeId = matchstat.ColorSchemeId;
checkMatchStat.PlayerName = matchstat.PlayerName;
mh.UpdateMatchStat(checkMatchStat);
}
Console.WriteLine("PutExtra " + intent.GetStringExtra("ActionMin" + cnt.ToString()) + " min " + intent.GetStringExtra("HomeScore" + cnt.ToString()) + "-" + intent.GetStringExtra("GuestScore" + cnt.ToString()));
}
SendBack(intent.GetStringExtra("Path"));
}
}
Using this method the syncing is much faster and more precise. No data is lost and all data is received and processed in the right order.
In a WPF window called from the MainWindow.xaml.cs I have a class I defined with multiple elements. I create an array of this class type.
In FieldLengths.xaml.cs I have:
public partial class FieldLengths : Window
{
public FieldJustifyFill[] fjfFields = new FieldJustifyFill[0];
public class FieldJustifyFill
{
public int ColumnNumber { get; set; }
public bool RightJustify { get; set; }
public bool LeftJustify { get; set; }
public bool LeftZeroFill { get; set; }
public bool RightZeroFill { get; set; }
}
I load is this way:
try
{
dtFields = ((DataView)dtGrid.ItemsSource).ToTable();
intNumFields = 0;
for (int intRowCnt = 0; intRowCnt < dtFields.Rows.Count; intRowCnt++)
{
bool blnJustifyRight = Convert.ToBoolean(dtFields.Rows[intRowCnt][2]);
bool blnJustifyLeft = Convert.ToBoolean(dtFields.Rows[intRowCnt][3]);
bool blnLeftZeroFill = Convert.ToBoolean(dtFields.Rows[intRowCnt][4]);
bool blnRightZeroFill = Convert.ToBoolean(dtFields.Rows[intRowCnt][5]);
if (blnJustifyRight || blnJustifyLeft || blnLeftZeroFill || blnRightZeroFill)
{
Array.Resize(ref fjfFields, intNumFields + 1);
fjfFields[intNumFields] = new FieldJustifyFill
{
ColumnNumber = intRowCnt,
RightJustify = blnJustifyRight,
LeftJustify = blnJustifyLeft,
LeftZeroFill = blnLeftZeroFill,
RightZeroFill = blnRightZeroFill
};
intNumFields += 1;
}
}
}
catch (Exception ex)
{
string strMsg;
strMsg = "RefreshRowSize, error '" + ex.Message + "' has occurred.";
System.Windows.MessageBox.Show(strMsg);
}
In MainWindow.xaml.cs I have this:
public partial class MainWindow : Window
{
FieldJustifyFillDest[] fjfFieldsDest = new FieldJustifyFillDest[0];
And in a routine I try to get the values from FixedLengths.xaml.cs like this:
FieldLengths flWin = new FieldLengths(strInputName, strFieldInfo, null, null, null, strMappingMetadata);
flWin.Left = System.Windows.Application.Current.MainWindow.Left + 15;
flWin.Top = desktopWorkArea.Top + 25;
flWin.ShowDialog();
if (flWin.blnFLCreateFile)
{
string strPrgFileName;
Array.Resize(ref fjfFieldsDest, flWin.fjfFields.Length);
for (int i = 0; i < flWin.fjfFields.Length; i++)
{
int intColumnNumber = flWin.fjfFields[i].ColumnNumber;
bool blnRightJustify = flWin.fjfFields[i].RightJustify;
bool blnLeftJustify = flWin.fjfFields[i].LeftJustify;
bool blnLeftZeroFill = flWin.fjfFields[i].LeftZeroFill;
bool blnRightZeroFill = flWin.fjfFields[i].RightZeroFill;
fjfFieldsDest[i] = new FieldJustifyFillDest
{
ColumnNumber = intColumnNumber,
RightJustify = blnRightJustify,
LeftJustify = blnLeftJustify,
LeftZeroFill = blnLeftZeroFill,
RightZeroFill = blnRightZeroFill
};
}
The variable intColumnNumber, blnRightJustify, blnLeftJustify, blnLeftZeroFill, blnRightZeroFill have the correct values but when it is loaded into fjfFieldsDest[i] they are not correct.
How do I return the class array correctly? I can not find a good example anywhere.
My apologies, my code is working correctly as coded. The debugger reordered the class elements alphabetically and I did not notice. Sorry all. However if the way I am coding it is not correct I welcome any feedback to code correctly.
I am working on a multi-level marketing (binary) which looks like this:
(but the binary tree is not required to be perfect. A node can have 0-2 child)
My problem is the data that I fetch from the database is flat list.
Notice that I am using hierarchyid (sql server 2014)
Basically the TextNode column is like a breadcrumb.
every slash / represents a level.
If I have TextNode of /1/ as root. then every node that starts with /1/ belongs to that root which are /1/, /1/1/ and /1/1/1/ (the root node is included which will be the level 0)
I've tried the accepted answer in this question but its not working.
How can I transform the flatlist to a Binary Tree so that I can easily traverse and display it on a screen?
Im using C#, ASP MVC 5, SQL Server 2014 if it matters.
I implement exactly this code According to Alex implementation but as is mentioned in some case it didn't work correctly .. have a look to my Image and my code (which copied from Alex post) [data in the database are correct but in tree view seems some problems ]
public class Row : IRow<string>
{
public string TextNode { get; }
public string Value { get; }
public long Id { get; }
public string FIN { get; }
public Row(string textNode, string userName, long id, string fin)
{
FIN = fin;
Id = id;
TextNode = textNode;
Value = userName;
}
}
public interface IRow<out T>
{
string TextNode { get; }
long Id { get; }
string FIN { get; }
T Value { get; }
}
public class TreeNode<T>
{
private struct NodeDescriptor
{
public int Level { get; }
public int ParentIndex { get; }
public NodeDescriptor(IRow<T> row)
{
var split = row.TextNode.Split(new[] { "/" }, StringSplitOptions.RemoveEmptyEntries);
Level = split.Length;
ParentIndex = split.Length > 1 ? int.Parse(split[split.Length - 2]) - 1 : 0;
}
}
public T title { get; }
public long Id { get; }
public string FIN { get; }
public List<TreeNode<T>> children { get; }
private TreeNode(T value, long id, string fin)
{
Id = id;
FIN = fin;
title = value;
children = new List<TreeNode<T>>();
}
public static TreeNode<T> Parse(IReadOnlyList<IRow<T>> rows)
{
if (rows.Count == 0)
return null;
var result = new TreeNode<T>(rows[0].Value, rows[0].Id, rows[0].FIN);
FillParents(new[] { result }, rows, 1, 1);
return result;
}
private static void FillParents(IList<TreeNode<T>> parents, IReadOnlyList<IRow<T>> rows, int index, int currentLevel)
{
var result = new List<TreeNode<T>>();
for (int i = index; i < rows.Count; i++)
{
var descriptor = new NodeDescriptor(rows[i]);
if (descriptor.Level != currentLevel)
{
FillParents(result, rows, i, descriptor.Level);
return;
}
var treeNode = new TreeNode<T>(rows[i].Value, rows[i].Id, rows[i].FIN);
parents[descriptor.ParentIndex].children.Add(treeNode);
result.Add(treeNode);
}
}
}
g
this is also my JSON output for more information :
{"title":"Earth","Id":32,"FIN":"FIN","children":[{"title":"Europe","Id":33,"FIN":"FIN001","children":[{"title":"France","Id":35,"FIN":"FIN001001","children":[{"title":"Paris","Id":36,"FIN":"FIN001001001","children":[]},{"title":"Brasilia","Id":41,"FIN":"FIN002001001","children":[]},{"title":"Bahia","Id":42,"FIN":"FIN002001002","children":[]}]},{"title":"Spain","Id":38,"FIN":"FIN001002","children":[{"title":"Madrid","Id":37,"FIN":"FIN001002001","children":[{"title":"Salvador","Id":43,"FIN":"FIN002001002001","children":[]}]}]},{"title":"Italy","Id":45,"FIN":"FIN001003","children":[]},{"title":"Germany","Id":48,"FIN":"FIN001004","children":[]},{"title":"test","Id":10049,"FIN":"FIN001005","children":[]}]},{"title":"South America","Id":34,"FIN":"FIN002","children":[{"title":"Brazil","Id":40,"FIN":"FIN002001","children":[{"title":"Morano","Id":47,"FIN":"FIN001003001","children":[]}]}]},{"title":"Antarctica","Id":39,"FIN":"FIN003","children":[{"title":"McMurdo Station","Id":44,"FIN":"FIN003001","children":[]}]}]}
Here is a very simple implementation (assuming that Nodes are in the right order), which may be enhanced in multiple ways
public interface IRow<out T>
{
string TextNode { get; }
T Value { get; }
}
public class TreeNode<T>
{
private struct NodeDescriptor
{
public int Level { get; }
public int ParentIndex { get; }
public NodeDescriptor(IRow<T> row)
{
var split = row.TextNode.Split(new [] {"/"}, StringSplitOptions.RemoveEmptyEntries);
Level = split.Length;
ParentIndex = split.Length > 1 ? int.Parse(split[split.Length - 2]) - 1 : 0;
}
}
public T Value { get; }
public List<TreeNode<T>> Descendants { get; }
private TreeNode(T value)
{
Value = value;
Descendants = new List<TreeNode<T>>();
}
public static TreeNode<T> Parse(IReadOnlyList<IRow<T>> rows)
{
if (rows.Count == 0)
return null;
var result = new TreeNode<T>(rows[0].Value);
FillParents(new[] {result}, rows, 1, 1);
return result;
}
private static void FillParents(IList<TreeNode<T>> parents, IReadOnlyList<IRow<T>> rows, int index, int currentLevel)
{
var result = new List<TreeNode<T>>();
for (int i = index; i < rows.Count; i++)
{
var descriptor = new NodeDescriptor(rows[i]);
if (descriptor.Level != currentLevel)
{
FillParents(result, rows, i, descriptor.Level);
return;
}
var treeNode = new TreeNode<T>(rows[i].Value);
parents[descriptor.ParentIndex].Descendants.Add(treeNode);
result.Add(treeNode);
}
}
}
Sample usage:
public class Row : IRow<string>
{
public string TextNode { get; }
public string Value { get; }
public Row(string textNode, string userName)
{
TextNode = textNode;
Value = userName;
}
}
class Program
{
static void Main(string[] args)
{
IRow<string>[] rows =
{
new Row("/", "Ahmed"),
new Row("/1/", "Saeed"),
new Row("/2/", "Amjid"),
new Row("/1/1/", "Noura"),
new Row("/2/1/", "Noura01"),
new Row("/2/2/", "Reem01"),
new Row("/1/1/1", "Under_noura")
};
var tree = TreeNode<string>.Parse(rows);
PrintTree(tree);
}
private static void PrintTree<T>(TreeNode<T> tree, int level = 0)
{
string prefix = new string('-', level*2);
Console.WriteLine("{0}{1}", prefix, tree.Value);
foreach (var node in tree.Descendants)
{
PrintTree(node, level + 1);
}
}
}
I have a list of comments formed. The client wants a new page after every 10 comments, so comment 11 will be on page 2, and so on for as many pages as they get. The commets are formed on a .ashx page becuase of an issue I had with the regular .aspx.cs page. Simply put, how do I accomplish this?
Here is the code of the .ashx page:
public void ProcessRequest (HttpContext context)
{
// ****************************************
if (context.Request["postform"] == "1")
{
videomessage myVideoMessage = new videomessage();
myVideoMessage.video_id = context.Request["video_id"];
myVideoMessage.first_name_submitter = context.Request["first_name_submitter"];
myVideoMessage.last_initial_submitter = context.Request["last_initial_submitter"];
myVideoMessage.message = context.Request["message"];
myVideoMessage.status = "0";
myVideoMessage.Save();
}
// ****************************************
// ****************************************
StringBuilder myStringBuilder = new StringBuilder();
// PULL VIDEOMESSAGES FOR VIDEO_ID
videomessage[] myCommentsList = new videomessage().Listing("video_id", context.Request["video_id"], "entry_date" , "DESC");
// FORM COMMENTS IF MORE THAN ONE COMMENT EXISTS
foreach (videomessage tmpMessage in myCommentsList)
{
if (tmpMessage.status == "0" || tmpMessage.status == "1")
{
myStringBuilder.Append("<div class=\"comment_box\">");
myStringBuilder.Append("<p class=\"comment_date\">");
myStringBuilder.Append(Utility.FormatShortDate(tmpMessage.entry_date) + " " + tmpMessage.first_name_submitter + " " + tmpMessage.last_initial_submitter + "." + "</p>");
if (!String.IsNullOrEmpty(tmpMessage.message))
{
myStringBuilder.Append("<p>" + tmpMessage.message + "</p>");
myStringBuilder.Append("</div>");
}
}
}
string return_str = myStringBuilder.ToString();
// IF NO COMMENTS RETURN THIS
if( String.IsNullOrEmpty(return_str) ) return_str = "<p>No comments currently exist for this video.</p>";
// ****************************************
// RETURN STRING
context.Response.ContentType = "text/plain";
context.Response.Write(return_str);
}
I know there will need to be some math involved as well as assigning it to variables, but I am still new to .NET so any help would be appreciated.
Thanks in advance!
using Linq
const int pageSize = 10;
var paginatedComments = comments.Skip((page ?? 0) * pageSize).Take(pageSize).ToList();
(*) page is input from request
Maybe a little outdated, but have a look at the nerddinner tutorial (http://aspnetmvcbook.s3.amazonaws.com/aspnetmvc-nerdinner_v1.pdf), which describes a pagination principle for MVC using a custom PaginatedList class
public class PaginatedList<T> : List<T> {
public int PageIndex { get; private set; }
public int PageSize { get; private set; }
public int TotalCount { get; private set; }
public int TotalPages { get; private set; }
public PaginatedList(IQueryable<T> source, int pageIndex, int pageSize) {
PageIndex = pageIndex;
PageSize = pageSize;
TotalCount = source.Count();
TotalPages = (int) Math.Ceiling(TotalCount / (double)PageSize);
this.AddRange(source.Skip(PageIndex * PageSize).Take(PageSize));
}
public bool HasPreviousPage {
get {
return (PageIndex > 0);
}
}
public bool HasNextPage {
get {
return (PageIndex+1 < TotalPages);
}
}
}
Alternative solution would be using a jquery approach (see http://www.jquery4u.com/plugins/10-jquery-pagination-plugins), but I have no experience with either of the plugins suggested on this site.
Have a look at this
currentPage=1
NextPageFirstRecord=(currrentpage-1)*noRecordsPerPage
pageCount=totalrecords/noRecordsPerPage
Hope this helps