Create hyperlinks in MVC Action Method - c#

I have an action method returning a JsonResult in my controller:
public JsonResult GetDetails()
{
var rows = //Linq-To-SQL
//Linq-To-Entities
var lifts = (from r in rows
group r by new { r.LiftID, r.LiftDate } into g
select new
{
ID = g.Key.LiftID,
Date = g.Key.LiftDate.ToShortDateString(),
Driver = g.Where(x => x.IsDriver)
.Select(x => x.p).Single().Name,
Passengers = g.Where(x => !x.IsDriver)
.Select(x => x.p.Name)
.Aggregate((x, y) => x + ", " + y)
}).ToList();
return Json(lifts);
}
I use the result in a jQuery script to write out a table.
The data looks like:
ID | Date | Driver | Passengers
1 | 20/06/2010 | David Neale | John Smith, Paul Jones
etc...
I would like the names to be hyperlinks to the route Person\{id} I.e. David Neale. The p property corresponds to a Person object containing both Name and ID.
I don't want to construct the URL manually. How would I construct the object to contain the names as hyperlinks using the MVC routing engine?

It's fairly easy.
Just use Url.Action("actionName", "controllerName", params)
It will create a string using the routing engine, so if you change the routes your code will keep workin just fine

First, I think you have a mistake in your model or in your Linq-To-SQL or Linq-To-Entities querys. Because you don't have an ID for your Persons (Drivers and Passagers), and you will definitly need it if you want a link with an Id of the Person. I think you need to split your Lifts from your Persons and have 2 separate entities (linked by its Id of course).
Second, you need to pass the ID of the Persons from the Controller to the View.
class Lift
{
public int LiftID { get; set; }
public DateTime LiftDate { get; set; }
public IEnumerable<Person> p { get; set; }
}
class Person
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsDriver { get; set; }
}
public JsonResult GetDetails()
{
var rows = new Lift[] { //Linq-To-SQL and Linq-To-Entities replaced by an example
new Lift{LiftID = 1, LiftDate= DateTime.Now, p = new Person[] {
new Person{IsDriver = true, Id = 1, Name = "David Neale"},
new Person{IsDriver = false, Id = 2, Name = "John Smith"},
new Person{IsDriver = false, Id = 3, Name = "Paul Jones"}
}},
new Lift{LiftID = 2, LiftDate= DateTime.Now, p = p = new Person[] {
new Person{IsDriver = true, Id = 4, Name = "Daniel Faraday"},
new Person{IsDriver = false, Id = 2, Name = "John Smith"}
}}
};
var lifts = (from r in rows
select new
{
ID = r.LiftID,
Date = r.LiftDate.ToShortDateString(),
Driver = r.p.Where(x => x.IsDriver)
.Select(x => x.Name).Single(),
Passengers = r.p.Where(x => !x.IsDriver)
.Select(x => x.Name)
.Aggregate((x, y) => x + ", " + y)
}).ToList();
return Json(lifts);
}
Then, once you have the ID on the View you use it to make the link using Html.ActionLink:
<%= Html.ActionLink("Person", "Index", new { id = p.Id })%>

If you know the action and controller beforehand, you can do something like:
var baseURL = '<%=Url.Action("MyAction","MyController") %>';
and then manually build your links from jQuery, with href set to something like baseUrl+"/"+personId

Related

Remove elements in a list considering duplicated subelements

I need to remove elements in a single list considering one or more duplicated subelement
Classes
public class Person
{
public int id { get; set; }
public string name { get; set; }
public List<IdentificationDocument> documents { get; set; }
public Person()
{
documents = new List<IdentificationDocument>();
}
}
public class IdentificationDocument
{
public string number { get; set; }
}
Code:
var person1 = new Person() {id = 1, name = "Bob" };
var person2 = new Person() {id = 2, name = "Ted" };
var person3 = new Person() {id = 3, name = "Will_1" };
var person4 = new Person() {id = 4, name = "Will_2" };
person1.documents.Add(new IdentificationDocument() { number = "123" });
person2.documents.Add(new IdentificationDocument() { number = "456" });
person3.documents.Add(new IdentificationDocument() { number = "789" });
person4.documents.Add(new IdentificationDocument() { number = "789" }); //duplicate
var personList1 = new List<Person>();
personList1.Add(person1);
personList1.Add(person2);
personList1.Add(person3);
personList1.Add(person4);
//more data for performance test
for (int i = 0; i < 20000; i++)
{
var personx = new Person() { id = i, name = Guid.NewGuid().ToString() };
personx.documents.Add(new IdentificationDocument() { number = Guid.NewGuid().ToString() });
personx.documents.Add(new IdentificationDocument() { number = Guid.NewGuid().ToString() });
personList1.Add(personx);
}
var result = //Here comes the linq query
result.ForEach(r => Console.WriteLine(r.id + " " +r.name));
Expected result:
1 Bob
2 Ted
3 Will_1
Example
https://dotnetfiddle.net/LbPLcP
Thank you!
You can use the Enumerable.Distinct<TSource> method from LINQ. You'll need to create a custom comparer to compare using the subelement.
See How do I use a custom comparer with the Linq Distinct method?
Well, yes, you could use a custom comparer. But that's going to be lots more code than your specific example requires. If your specific example is all you need, this this will work fine:
var personDocumentPairs = personList1
.SelectMany(e => e.documents.Select(t => new {person = e, document = t}))
.GroupBy(e => e.document.number).Select(e => e.First());
var result = personDocumentPairs.Select(e => e.person).Distinct();
along the lines of Adam's solution the trick is to iterate persons and group them by associated document numbers.
// persons with already assigned documents
// Will_2
var duplicate = from person in personList1
from document in person.documents
group person by document.number into groupings
let counter = groupings.Count()
where counter > 1
from person in groupings
.OrderBy(p => p.id)
.Skip(1)
select person;
// persons without already assigned documents
// Bob
// Ted
// Will_1
var distinct = from person in personList1
from document in person.documents
group person by document.number into groupings
from person in groupings
.OrderBy(p => p.id)
.Take(1)
select person;
the orderby is a made up rule for the already assigned documents persons, but your mileage may vary

LinQ nested lists and nested selects

Consider these two tables:
ClassID Name
1 C1
2 C2
ClassID List<CourseSession>
1 [Object that has value "A"], [Object that has value "B"]
2 [Object that has value "B"], [Object that has value "C"]
When I join these two tables in Linq, I get:
ID Name List
1 C1 [A, B]
2 C2 [A, B]
Wheras I need to expand them:
ID Name List
1 C1 A
1 C1 B
2 C2 A
2 C2 B
Linq code:
var classes = from row in t.AsEnumerable()
select new
{
ClassID = row.Field<Guid>("ClassID"),
ClassName = row.Field<string>("Name"),
};
var classCourses = from row in classes.AsEnumerable()
select new
{
ID = row.ID,
CourseSessionList = GetAllCoursesByID(row.ID).AsEnumerable()
};
//Attempt to join
var expandedClassCourse = from classRow in classes
join ccRow in classCourses
on classRow.ID equals ccRow.ID
into filteredExpandedClasses
select filteredExpandedClasses;
I'm not sure how to achieve this. Any ideas?
Something like (not sure what your model looks like):
context.CouseSessions.Where(cs => /* condition goes here */)
.Select(cs =>
new
{
Name = cs.Name,
Class = cs.Class.Name
});
or
context.Classes.Where(c => /* condition goes here */)
.SelectMany(c => c.Courses)
.Select(cs =>
new
{
Name = cs.Name,
Class = cs.Class.Name
});
I created two models based on assumption. I hope this helps.
class Info
{
public int Id { get; set; }
public string Name { get; set; }
public List<string> List { get; set; }
}
class MyClass
{
public int Id { get; set; }
public string Name { get; set; }
public string s { get; set; }
}
static void Main(string[] args)
{
var infos = new List<Info> { new Info { Id = 1, Name = "c1", List = new List<string> { "A", "B" } }, new Info { Id = 2, Name = "c2", List = new List<string> { "A", "B" } } };
var myClasses = new List<MyClass>();
foreach (var info in infos)
{
myClasses.AddRange(info.List.Select(a => new MyClass { Id = info.Id, Name = info.Name, s = a }));
}
}
(from c in classList
join s in sessionList on c.ClassID equals s.ClassID
select new
{
ID = c.ClassID,
Name = c.Name,
SessionList = s.SessionList
})
.SelectMany(e => e.SessionList.Select(s => new
{
ID = e.ClassID,
Name = e.Name,
Session = s
}))

List in list (Model) Factory

I would like to create list of data in list of data. I believe this can be difficult to explain but I will try explain my problem very clear. I created list of data but in this list some arguments are also list of data. I have to write using this code because this are restriction (Our Factory). If I take data, which are not list of data, everything working correct. Where is problem? If I write list in list I get error. Perhaps you can see there my mistake.
Program is compile.
Problem(I take data from third table using mapping in NHibernate):
DestynationName = (List<dictionaryNewInfoSupportList>x.DictImportantInformationSDestination.Select(n=> new DictionaryNewInfoSupportList { Id = n.Destination.Id, Name = n.Destination.Desciption}).ToList();
DestynationName in Model
public Ilist<dictionaryNewInfoSupportList> DestynationName;
Class:
class dictionaryNewInfoSupportList
{
public string Name {get; set;}
public int Id {get; set;}
}
Important:
public IEnumerable<DictionaryListModel> OnList(DictionayDisplayModel dictionary DisplayModel, int jtStartIndex = 0, int jtPageSize = 0, string jtSorting = null)
{
var displayModel = (DictionaryNewInfoDisplayModel)dictionaryDisplayModel;
if (displayModel == null)
var list = _dictImportantInformation.GetList().Select(
x=> new DictionaryNewInfoListModel
{
Id = x.Id
Description = x.Description,
IsActiveYN = x.IsActive,
DestynationName = (List<DictionaryNewInfoSupportList>) x.DictImportantInformationXDestination.Select(n => new DictionaryNewInfoSupportList
{ Id = n.Destination.Id, Name = Destination.Description}).To.List()
}
).ToList();
return list;
}
I have got answer (Topic Closed)
var list = _dictImportantInformation.GetList().ToList().Select(
x => new DictionaryNewInfoListModel
{
Id = x.Id,
Description = x.Description,
IsActiveYN = x.IsActive,
DeestynationName = x.DictImportantInformationXDestination.Select(n => new DictionaryNewInfoSupportList
{ Id = n.Destination.Id, Name = n.Destination.Description }).ToList()
}
).ToList();
var list = _dictImportantInformation.GetList().ToList().Select(
x => new DictionaryNewInfoListModel
{
Id = x.Id,
Description = x.Description,
IsActiveYN = x.IsActive,
DeestynationName = x.DictImportantInformationXDestination.Select(n => new DictionaryNewInfoSupportList
{ Id = n.Destination.Id, Name = n.Destination.Description }).ToList()
}
).ToList();

Filtering a List using lambda

I have an object which has properties ID, brandID, brandName, NumPages, and Type.
i need to show the top 5 brands by numPage size, a brand may have multiple IDs, so I need to group by brand
listing.OrderByDescending(o => o.numPage).GroupBy(o=> o.brandName).Take(5).ToList();
is alone the lines of what im looking for but this is not valid code.
It sounds like a given brand name may have several ID's and that you want the top 5 brand's sorted by numPage. Is that correct
If so try the following
var query = listing
.GroupBy(x => x.brandName)
.OrderByDescending(brands => brands.Sum(x => x.numPage))
.Select(x => x.Key)
.Take(5);
Note: After the GroupBy operation you're now passing around a collection of the brand objects instead of single ones. Hence to order by the numPage we need to sum it for all of the brand objects in the group. The .Select(x => x.Key) will select back out the original brandName on which the group is based
just tried and it works:
public class Listing
{
public int ID { get; set; }
public int BrandID { get; set; }
public string BrandName { get; set; }
public int NumPages { get; set; }
public Type Type { get; set; }
}
Here the filtering
Listing listing1 = new Listing() { NumPages = 2, BrandName = "xx" };
Listing listing2 = new Listing() { NumPages = 2, BrandName = "xx" };
Listing listing3 = new Listing() { NumPages = 2, BrandName = "xx" };
Listing listing4 = new Listing() { NumPages = 3, BrandName = "xxxxx" };
List<Listing> allListings = new List<Listing>() { listing1, listing2, listing3, listing4 };
var result = allListings.OrderByDescending(x => x.NumPages).GroupBy(x => x.BrandName).Take(5);

Group by with multiple columns using lambda

How can I group by with multiple columns using lambda?
I saw examples of how to do it using linq to entities, but I am looking for lambda form.
var query = source.GroupBy(x => new { x.Column1, x.Column2 });
I came up with a mix of defining a class like David's answer, but not requiring a Where class to go with it. It looks something like:
var resultsGroupings = resultsRecords.GroupBy(r => new { r.IdObj1, r.IdObj2, r.IdObj3})
.Select(r => new ResultGrouping {
IdObj1= r.Key.IdObj1,
IdObj2= r.Key.IdObj2,
IdObj3= r.Key.IdObj3,
Results = r.ToArray(),
Count = r.Count()
});
private class ResultGrouping
{
public short IdObj1{ get; set; }
public short IdObj2{ get; set; }
public int IdObj3{ get; set; }
public ResultCsvImport[] Results { get; set; }
public int Count { get; set; }
}
Where resultRecords is my initial list I'm grouping, and its a List<ResultCsvImport>. Note that the idea here to is that, I'm grouping by 3 columns, IdObj1 and IdObj2 and IdObj3
if your table is like this
rowId col1 col2 col3 col4
1 a e 12 2
2 b f 42 5
3 a e 32 2
4 b f 44 5
var grouped = myTable.AsEnumerable().GroupBy(r=> new {pp1 = r.Field<int>("col1"), pp2 = r.Field<int>("col2")});
Further to aduchis answer above - if you then need to filter based on those group by keys, you can define a class to wrap the many keys.
return customers.GroupBy(a => new CustomerGroupingKey(a.Country, a.Gender))
.Where(a => a.Key.Country == "Ireland" && a.Key.Gender == "M")
.SelectMany(a => a)
.ToList();
Where CustomerGroupingKey takes the group keys:
private class CustomerGroupingKey
{
public CustomerGroupingKey(string country, string gender)
{
Country = country;
Gender = gender;
}
public string Country { get; }
public string Gender { get; }
}
class Element
{
public string Company;
public string TypeOfInvestment;
public decimal Worth;
}
class Program
{
static void Main(string[] args)
{
List<Element> elements = new List<Element>()
{
new Element { Company = "JPMORGAN CHASE",TypeOfInvestment = "Stocks", Worth = 96983 },
new Element { Company = "AMER TOWER CORP",TypeOfInvestment = "Securities", Worth = 17141 },
new Element { Company = "ORACLE CORP",TypeOfInvestment = "Assets", Worth = 59372 },
new Element { Company = "PEPSICO INC",TypeOfInvestment = "Assets", Worth = 26516 },
new Element { Company = "PROCTER & GAMBL",TypeOfInvestment = "Stocks", Worth = 387050 },
new Element { Company = "QUASLCOMM INC",TypeOfInvestment = "Bonds", Worth = 196811 },
new Element { Company = "UTD TECHS CORP",TypeOfInvestment = "Bonds", Worth = 257429 },
new Element { Company = "WELLS FARGO-NEW",TypeOfInvestment = "Bank Account", Worth = 106600 },
new Element { Company = "FEDEX CORP",TypeOfInvestment = "Stocks", Worth = 103955 },
new Element { Company = "CVS CAREMARK CP",TypeOfInvestment = "Securities", Worth = 171048 },
};
//Group by on multiple column in LINQ (Query Method)
var query = from e in elements
group e by new{e.TypeOfInvestment,e.Company} into eg
select new {eg.Key.TypeOfInvestment, eg.Key.Company, Points = eg.Sum(rl => rl.Worth)};
foreach (var item in query)
{
Console.WriteLine(item.TypeOfInvestment.PadRight(20) + " " + item.Points.ToString());
}
//Group by on multiple column in LINQ (Lambda Method)
var CompanyDetails =elements.GroupBy(s => new { s.Company, s.TypeOfInvestment})
.Select(g =>
new
{
company = g.Key.Company,
TypeOfInvestment = g.Key.TypeOfInvestment,
Balance = g.Sum(x => Math.Round(Convert.ToDecimal(x.Worth), 2)),
}
);
foreach (var item in CompanyDetails)
{
Console.WriteLine(item.TypeOfInvestment.PadRight(20) + " " + item.Balance.ToString());
}
Console.ReadLine();
}
}

Categories

Resources