I am using visjs.net to display a schedule
I'm having trouble writing LINQ to populate a list that contains a property that is an array
Here is the visjs documentation visjs doco
and some example code visjs source code
Here is an abridged version of the sample in javascript. I need to populate this JSON from a MVC controller instead of javascript
var groups = new vis.DataSet();
groups.add([
{
id: 1,
content: "Lee",
nestedGroups: [11,12]
}
]);
groups.add([
{
id: 11,
content: "cook",
},
{
id: 12,
content: "shop",
}
]);
spoiler alert: I don't know how to populate the nestedGroups property
This is the class I built for it:
public class TimelineGroups
{
public int id { get; set; }
public string content { get; set; }
public string className { get; set; }
public string orderBy { get; set; }
public string[] nestedGroups { get; set; }
}
This is the controller method that populates it, excluding the nestedGroups property, and this works just fine:
public JsonResult EmployeeGroups()
{
List<TimelineGroups> e = (
from emp in db.Employees
where emp.Emp_Status == 1 && emp.EmployeeRole.IsChargeable == "Y"
orderby emp.EmpRole_ID, emp.Emp_Last_Name
select new TimelineGroups()
{
id = emp.Emp_ID,
content = emp.Emp_Name,
orderBy = emp.EmpRole_ID.ToString(),
className = "bte-" + emp.EmployeeRole.EmpRoleName
}
).ToList();
return Json(e, JsonRequestBehavior.AllowGet);
}
This all works correctly but now I want to add nested groups.
But I don't know the LINQ required to 'pivot' the required data into an array inside a collection.
This is what I have so far:
public JsonResult EmployeeClientGroups()
{
// First load the client list which are children of employees
List<TimelineGroups> cg = (
from sw in db.ScheduleWorks
where sw.EndDate > DateTime.Now
select new TimelineGroups()
{
id = sw.Employee.Emp_ID * 1000 + sw.CustomerId,
content = sw.Customer.Customer_Name
}).Take(1000).Distinct().ToList();
// now load the employee list
// This includes client children
List<TimelineGroups> eg = (
from sw in db.ScheduleWorks
where sw.EndDate > DateTime.Now
select new TimelineGroups()
{
id = sw.Employee.Emp_ID,
// How do I populate this with sw.Employee.Emp_ID * 1000 + sw.CustomerId
nestedGroups = // What magic do I put here?
content = sw.Employee.Emp_Name,
}).Take(1000).Distinct().ToList();
// Add the employee groups to the client groups
cg.AddRange(eg);
return Json(cg, JsonRequestBehavior.AllowGet);
}
I need to get all the client ID's for a given Employee and "pivot" them into an array, suitable to post back as JSON
To make them unique and match the children id's, the value I need to pivot in is:
sw.Employee.Emp_ID * 1000 + sw.CustomerId
Can this be done inline in a LINQ statement?
So it turns out this was kind of answered here but I will document my solution
This is the code that I eventually used:
public class TimelineGroups
{
public string id { get; set; }
public string content { get; set; }
public string className { get; set; }
public string orderBy { get; set; }
public List<string> nestedGroups { get; set; }
}
List<TimelineGroups> eg = (
from sw in db.ScheduleWorks
where sw.EndDate > DateTime.Now
where sw.Employee.Emp_Status == 1
group (sw.EmployeeId.ToString() + "." + sw.CustomerId.ToString())
by new {
id = sw.EmployeeId.ToString(),
EmpName = sw.Employee.Emp_Name,
EmpOrder = sw.Employee.EmpRole_ID.ToString()
}
into g
select new TimelineGroups()
{
id = g.Key.id,
// find the list of employee+client keys
nestedGroups = g.ToList(),
content = g.Key.EmpName,
orderBy = g.Key.EmpOrder
})
.Take(1000)
.ToList();
Note no Distinct
The argument to group is the field holding the values that i want to "pivot"
then the part after by is the actual 'key' that will be grouped on
I needed to use a List() rather than an array (maybe I could've used ToArray though?)
Once this is grouped into an intermediate variable g, you can use g.ToList() to get the 'pivoted' values
Hopefully this will help someone else one day, maybe even someone using the visjs library
#Tetsuya Yamamoto fiddle pointed me in the right direction
Related
I am using Linq to SQL in a WebApi to return a list of objects from a database to a frontend.
Let's say the model looks something like this:
public class Course
{
public int ID { get; set; }
public string NAME { get; set; }
}
public class Schedules
{
public int id { get; set; }
public int courseid
public datetime start { get; set; }
}
In addition my Linq-to-SQL inside of one Controller looks something like this:
...
...
var list = (from xx in xx.Courses
select new Course
{
ID = xx.ID,
NAME = xx.NAME,
Schedules = (from yy in yy.Schedules
where xx.ID == yy.courseid
select new Schedules
{
id = yy.id,
courseid = yy.courseid,
start = yy.start
}).toList()
}).toList()
...
...
Now I need to order "list" by the minValue of Schedules.start in an ascending order. That means, that the output should give me the element with the earliest start first. In addition Courses with no planned schedule should be given out at the end.
In the end the output should look like this:
[{"ID":5, "NAME":"NAME1", "Schedules":[{"id":10, "courseid":5, "start":"2017-12-15 00:00:00.000"}, {"id":8, "courseid":5, "start":"2017-12-20 00:00:00.000"}]}],[{"ID":1, "NAME":"NAME1", "Schedules":[{"id":9, "courseid":1, "start":"2017-12-16 00:00:00.000"}, {"id":2, "courseid":1, "start":"2017-12-17 00:00:00.000"}]}]
Thanks in advance.
I was in such a situation where I need to sort the parent depend on the child property's value.
var list = (from xx in xx.Courses
select new Course
{
ID = xx.ID,
NAME = xx.NAME,
Schedules = (from yy in yy.Schedules
where xx.ID == yy.courseid
select new Schedules
{
id = yy.id,
courseid = yy.courseid,
start = yy.start
}).toList()
}).OrderBy(mc => mc.Schedules.Min(dc => dc.start)).toList()
It's very simple for the user.
They select the type of part, manufacturer from a ComboBox, and search the part code in a text box. Click search and the results return in a DataGridView.
Code:
var mType = CmbType.SelectedItem.ToString();
var mManufacturer = CmbMfr.SelectedValue.ToString();
var mCode = Convert.ToString(TxtProductCode.Text);
switch (mType)
{
case "Faucets":
var faucets = Resources.Accessor.SearchFaucets(mManufacturer, mCode);
DgInventory.DataSource = faucets;
break;
case "Parts":
var parts = Resources.Accessor.SearchParts(mManufacturer, mCode);
DgInventory.DataSource = parts;
break;
}
Accessor Code:
public static List<TblFaucets> SearchFaucets(string mId, string mCode)
{
var dataConnect = new PxLinqSqlDataContext();
return (from f in dataConnect.GetTable<TblFaucets>()
where (f.Mfr == Convert.ToInt32(mId))
where (f.Code == mCode)
select f).ToList<TblFaucets>();
}
What "messes up" is the results:
ID: correct
Mfr: is the ID from its table, not the name
Code: Correct
Description: correct
Price: correct
Date: correct
Manufacturer: I don't know why this is even here, its result is "PXDB.TblManufacturers
First, PXDB.TblManufacturers seems to be a relation from tblFaucets to tblManufactureres.
Mfr seems to be the foreignKey value within your faucets table refering to a manufacturer.
You may try creating an anonymous type holding only those data you want to. Within your select clause pick your data - as well as any relational data.
public static List<DisplayFaucet> SearchFaucets(string mId, string mCode)
{
var dataConnect = new PxLinqSqlDataContext();
return (from f in dataConnect.GetTable<TblFaucets>()
where (f.Mfr == Convert.ToInt32(mId))
where (f.Code == mCode)
select new DisplayFaucet () { // create anonymous object
ID = f.ID, // only holding the data you want to
Manufacturer = Manufacturer.Name, // assuming there is property Name within your manufacturer table?!
Code = f.Code,
Description = f.Description,
Price = f.Price,
Date = f.Date
}).ToList();
}
Add another class to hold your data to display
public class DisplayFaucet
{
public int ID { get; set; }
public string Manufacturer { get; set; }
public string Code { get; set; } // check type
public string Description { get; set; }
public doublePrice{ get; set; } // check type
public DaetTime Date { get; set; } // check type
}
Note that SearchFaucets(..) may no longer return items of type tblFaucet! Instead I created a new class. This one contains all data which should be displayed!
I'm not really sure if what i'm looking for actually exists, so maybe you guys can help out.
I have the below data:
Apples|3211|12
Markers|221|9
Turtle|1023123123|22
The first column is always a string, the second column and third column are ints. However, what I want to do is be able to reference theses as strings or ints, and then be able to sort via the third column asc. Any ideas?
Something like MyTable[i].Column[i] and in this case MyTable[1].Column[2] would produce 12 as a int (because it's ordered).
If you want type safety you will need to create a class that holds each record:
class Record
{
string Name { get; set; }
int SomeValue { get; set; }
int OrderNr { get; set; }
}
Afterwards store them in a generic List<>, then you can order them, as you like:
List<Record> items = // read them into a list of items;
List<Record> orderedList = items.OrderBy(i => i.OrderNr).ToList();
UPDATE
Since it was requested I customized the answer from JustinNiessner to fit to my example:
string data = // your data as string
List<Record> records = data
.Split('|')
.Select(item => new Record
{
Name = item[0],
SomeValue = int.Parse(item[1]),
OrderNr = int.Parse(item[2])
}).ToList();
List<Record> orderedRecords = records.OrderBy(r => r.OrderNr).ToList();
This can be optimized by using var and not executing ToList() on the list, but is done this way in order to keep it simple for you to understand the concepts better.
Assuming you have your data stored in some sort of IEnumerable<string> type, you could try something like:
var sortedObjs = stringRows
.Split('|')
.Select(r => new
{
ColA = r[0],
ColB = int.Parse(r[1]),
ColC = int.Parse(r[2])
})
.OrderBy(r => r.ColC).ToList();
var specificVal = sortedObjs[1].ColC;
This speaks to a larger problem in your design. Using collections to hold a bunch of disparate types with the intent of organizing them into some sort of structure is fragile, error prone, and completely unnecessary.
Instead, create your own type to organize this information.
class MyType
{
public string Name { get; set; }
public int Whatever { get; set; }
public int AnotherProp { get; set; }
}
Now your data is logically grouped in a nice, tight, type safe package.
Your original post didn't specify what the ints were, but since you wanted to select them either by the Descripton(?) or the Id(?) and then sort them by the third column perhaps something like this will work for you?
//Code tested in LinqPad
void Main()
{
//Apples|3211|12
//Markers|221|9
//Turtle|1023123123|22
//Create a list of items
var items = new List<Item>
{
new Item { Description = "Apple", Id = 3211, Sequence = 12 },
new Item { Description = "Markers", Id = 221, Sequence = 9 },
new Item { Description = "Turtle", Id = 1023123123, Sequence = 22 }
};
//Get sorted list of Apple by Description
var sortedByDescription = items.Where(i => i.Description == "Apple").OrderBy(i => i.Sequence);
//Get sorted list of Turtle by Id
var sortedById = items.Where(i => i.Id == 221).OrderBy(i => i.Sequence);
}
public class Item
{
public string Description { get; set; }
public int Id { get; set; }
public int Sequence { get; set; }
}
i have an act:
public class Act
{
public Act()
{
this.Tags = new List<Tag>();
}
public string Id {get; set;}
public string Name { get; set; }
public IList<Tag> Tags { get; set; }
}
Tag is just:
public class Tag
{
public string Name { get; set; }
public string LfmUrl { get; set; }
}
I want to be able to query the DB and get a list of TagCount back which shows the name of the tag and the number of times it appears.
So far I have this:
public class Tags_ByTagCloud : AbstractIndexCreationTask
{
public override IndexDefinition CreateIndexDefinition()
{
return new IndexDefinition<Act, TagAndCount>
{
Map = docs => from doc in docs
from tag in doc.Tags
select new
{
Name = tag.Name,
Count = 1
},
Reduce = results => from result in results
group result by result.TagName
into g
select new
{
Name = g.Key,
Count = g.Sum(x => x.Count)
},
SortOptions = {{x => x.Count, SortOptions.Int}}
}.ToIndexDefinition(DocumentStore.Conventions);
}
}
Which happily outputs nothing. I know there are thousands of acts each with at least a few tags. Any ideas?
I ideally want to pass in a list of act ids to query this against. So, given a list of acts, what are the tags and how many times does
each occur?
Just had to change all TagName to match Name and it mapped nicely
I have a collection of TwitterCollection objects held within a List. I am populating the TwitterCollection object (tc) via a foreach loop, and then accessing it through LINQ.
My class with its properties looks like this:
//simple field definition class
public class TwitterCollection
{
public string origURL { get; set; }
public string txtDesc { get; set; }
public string imgURL { get; set; }
public string userName { get; set; }
public string createdAt { get; set; }
public string realURL { get; set; }
public string googleTitle { get; set; }
public string googleDesc { get; set; }
}
I then go on to populate it with a loop through a bunch of RegEx matches in a group:
var list = new List<TwitterCollection>();
foreach (Match match in matches)
{
GroupCollection groups = match.Groups;
var tc = new TwitterCollection
{
origURL = groups[1].Value.ToString(),
txtDesc = res.text,
imgURL = res.profile_image_url,
userName = res.from_user_id,
createdAt = res.created_at,
};
list.Add(tc);
}
Finally I am looking at the collection with LINQ and extracting only certain items for display:
var counts = from URL in list
group URL by URL into g
orderby g.Count()
select new { myLink = g.Key, Count = g.Count() };
The outcome of all this is a long list of the word "TwitterCollection" in count.myLink and no count of URLs...
I used to have this all working before I shifted to a generic List. Now I have moved for convenience, it won't work.
I'd seriously appreciate someone taking me out of my misery here! Thanks in advance.
Your list is of type List<TwitterCollection>, so the URL variable is of type TwitterCollection. So a TwitterCollection is what gets selected into g.Key (and hence myLink), and that gets rendered as the string "TwitterCollection".
Change your query to:
var counts = from tc in list
group tc by tc.origURL into g // note by tc.origURL to extract the origURL property
...
(It's not clear from your code which URL you want to group on, as a TwitterCollection contains several URLs. I've used origURL as an example.)