I am having trouble dynamically specifying the column and direction to sort on.
I currently have the following code:
if (sort != "OrderID")
{
if (sort == "EmployeeName")
{
sort = "Employee.FirstName"; //sort by Employee FirstName
}
else
{
sort = "Customer." + sort; //Customer.CompanyName sort
}
}
var sortCriteria = string.Format("{0} {1}", sort, sortDir);
var res1 = nwd.Orders //response
.OrderBy(o => sort+" "+sortDir)
.ThenBy(o => o.OrderID)
.Skip((page - 1) * rowsPerPage)
.Take(rowsPerPage)
.Select(o => new
{
o.OrderID,
o.Customer.CompanyName,
o.Customer.ContactName,
o.Employee.FirstName,
o.Employee.LastName,
o.Order_Details
}).ToList();
Any help would be much appreciated!
How about this?
var res1 = nwd.Orders //response
IOrderedQueryable<Orders> result;
if (sort != "OrderID")
{
if (sort == "EmployeeName")
{
result = res1.OrderBy(o => o.Employee.FirstName);
}
else
{
result= res1.OrderBy(o => o.Customer.CompanyName);
}
}
result = result.ThenBy(o => o.OrderID)
.Skip((page - 1) * rowsPerPage)
.Take(rowsPerPage)
.Select(o => new
{
o.OrderID,
o.Customer.CompanyName,
o.Customer.ContactName,
o.Employee.FirstName,
o.Employee.LastName,
o.Order_Details
}).ToList();
Ok, here's a working example with a dummy class:
internal class Program
{
private static void Main(string[] args)
{
var list_people = new List<Person> {
new Person() {Age = 4, Name = "yo"},
new Person() {Age = 5, Name = "a"}
};
var dynamic_propretry = typeof (Person).GetProperty("Name");
var sorted = list_people.OrderBy(person => dynamic_propretry.GetValue(person, null));
foreach (var person in sorted)
{
Console.Out.WriteLine(person);
}
Console.ReadLine();
}
}
public class Person{
public int Age { get; set; }
public string Name { get; set; }
public override string ToString()
{
return Name + ":" + Age;
}
}
So, all you have to do is store the property you want in a string, and just use that string where I used "Name". It should work.
Related
I am trying to convert object to a string using SelectMany. However when list property value is empty then I am not getting desired string.
I am expecting results like
name1-2-4 : name2-
but getting this result as
name1-2-4
. The second name is ignored because of "Scores" list which is empty.
using System;
using System.Linq;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
var person1 = new Person()
{
Name = "name1",
Scores = new List<Score>
{
new Score
{
InitialScore =2,
UpdatedScore = 4
}
}
};
var person2 = new Person()
{
Name = "name2",
Scores = new List<Score>()
};
var persons = new List<Person>();
persons.Add(person1);
persons.Add(person2);
var result = string.Join(" : ", persons.SelectMany(x=>x.Scores, (parent, child)=> parent.Name + "-" + child.InitialScore +"-"+ child.UpdatedScore));
Console.WriteLine(result);
}
}
public class Person
{
public string Name {get; set;}
public List<Score> Scores {get; set;}
}
public class Score
{
public int InitialScore {get; set;}
public int UpdatedScore {get; set;}
}
Edit:
Based on #JonasH solution use this linq query.
var result = string.Join(" : ", persons.SelectMany(x=>GetNames(x)));
A simple solution would be to add a helper method to your person that does what you want:
public static IEnumerable<string> GetNames(this Person p)
{
if (p.Scores.Count == 0)
{
yield return p.Name;
}
else
{
foreach (var score in p.Scores)
{
yield return $"{p.Name}-{score}";
}
}
}
and use that instead of .Scores in SelectMany.
var result1 = persons.SelectMany(x => x.Scores, (parent, child) => parent.Name + "-" + child.InitialScore + "-" + child.UpdatedScore).FirstOrDefault();
var result2 = persons.Where(x => x.Scores.Count() <= 0).Select(x => x.Name).FirstOrDefault()+"-";
var result = $"{result1}:{result2}";
Object
namespace Example
{
public class ContractorAddValue
{
public Member Member { get; set; }
public List<Addresses> Addresses { get; set; }
public ICommand AddAddress { get; set; }
}
public class Addresses
{
public MemberAddress MemberAddress { get; set; }
public ICommand EditAddress { get; set; }
}
}
Query
public ObservableCollection<ContractorAddValue> GetContractorsOrderByCity()
{
var allContractors = (from c in db.Member where c.IsContrator == true select c).ToList();
//var allContractors2 = db.Member .Include(c => c.MemberAddress).SelectMany(c => c.MemberAddress).OrderBy(c => c.City).Select(c => c.Member ).ToList();
//var allContractors = (from c in db.Member where c.IsContrator == true select c).OrderBy(c => c.MemberAddress.OrderBy(x => x.City)).ToList(); <= dosent work
var listContractorAddValue = new ObservableCollection<ContractorAddValue>();
foreach (var i in allContractors)
{
var adressList = db.MemberAddress.Where(x => x.MemberId == i.MemberId).OrderBy(x => x.City).ToList();
ContractorAddValue contractorAddValue = new ContractorAddValue();
contractorAddValue.Member = i;
contractorAddValue.AddAddress = new BaseCommand(() => ContractorsViewModel.SendAddress(i.MemberId ));
contractorAddValue.Addresses = new List<Addresses>();
foreach (var a in adressList)
{
Addresses memberAdress = new Addresses();
memberAdress.MemberAddress = a;
memberAdress.EditAddress = new BaseCommand(() => ContractorsViewModel.SendEditAddress(a.MemberAddressId , i.MemberId ));
contractorAddValue.Addresses.Add(memberAdress);
}
listContractorAddValue.Add(contractorAddValue);
}
return listContractorAddValue;
}
allContractors2 - the order by works, but I retrieve repeating Members. In this approach I tried to use .Distinct() after Select(c => c.Member) but it doesn't work (the whole query stops working).
My goal is to make an order by MemberAddress.City
Thanks in advance!
I think that this code will work but you need to redefine the Equals method of the ContractorAddValue class.
I added one if statement when you want to add contractorAddValue to the list. First you need to check if your list contains that object. If not you add the object to the list. If yes you need to find that object and merge its addresses list with addresses list from the object you want to add.
public ObservableCollection<ContractorAddValue> GetContractorsOrderByCity()
{
var allContractors = (from c in db.Member where c.IsContrator == true select c).ToList();
//var allContractors2 = db.Member .Include(c => c.MemberAddress).SelectMany(c => c.MemberAddress).OrderBy(c => c.City).Select(c => c.Member ).ToList();
//var allContractors = (from c in db.Member where c.IsContrator == true select c).OrderBy(c => c.MemberAddress.OrderBy(x => x.City)).ToList(); <= dosent work
var listContractorAddValue = new ObservableCollection<ContractorAddValue>();
foreach (var i in allContractors)
{
var adressList = db.MemberAddress.Where(x => x.MemberId == i.MemberId).OrderBy(x => x.City).ToList();
ContractorAddValue contractorAddValue = new ContractorAddValue();
contractorAddValue.Member = i;
contractorAddValue.AddAddress = new BaseCommand(() => ContractorsViewModel.SendAddress(i.MemberId ));
contractorAddValue.Addresses = new List<Addresses>();
foreach (var a in adressList)
{
Addresses memberAdress = new Addresses();
memberAdress.MemberAddress = a;
memberAdress.EditAddress = new BaseCommand(() => ContractorsViewModel.SendEditAddress(a.MemberAddressId , i.MemberId ));
contractorAddValue.Addresses.Add(memberAdress);
}
if(!listContractorAddValue.Contains(contractorAddValue)){
listContractorAddValue.Add(contractorAddValue);
} else {
var contAddValue = listContractorAddValue.First(l => l.Equals( contractorAddValue));
contAddValue.Addresses.AddRange(contractorAddValue.Addresses);
}
}
return listContractorAddValue;
}
I have two list different types (because they represents two different types in two different databases):
public partial class PersonOne
{
public int id { get; set; }
public string name { get; set; }
public string surname { get; set; }
public string address { get; set; }
public string phone { get; set; }
}
public partial class PersonTwo
{
public int id { get; set; }
public string firstname { get; set; }
public string lastname { get; set; }
public string email { get; set; }
}
I want to eliminate duplicates with the same firstname and lastname on the List and then take from that list objects which have got different firstname and lastname than objects on the List. Firstname in the class PartTwo = name in the class PartOne and lastname in the class PartTwo = surname in the class PartTwo.
I have that code but it is very slow:
List<PersonOne> personOneList = new List<PersonOne>(); // very big list
List<PersonTwo> personTwoList = new List<PersonTwo>(); // very big list
List<PersonTwo> difference = personTwoList
.GroupBy(x => new { FirstName = x.firstname.ToLower(), LastName = x.lastname.ToLower() })
.Select(x => x.First())
.Where(x => !personOneList.Any(y => y.name.Equals(x.firstname, StringComparison.InvariantCultureIgnoreCase) && y.surname.Equals(x.lastname, StringComparison.InvariantCultureIgnoreCase)))
.ToList();
Try this:
var HashTable = new Dictionary<Tuple<String,String>,Object>();
foreach (PersonOne person in personOneList)
{
var personTuple = Tuple.Create(person.name, person.surname);
if (!HashTable.ContainsKey(personTuple))
{
HashTable[personTuple] = person;
}
}
foreach (PersonTwo person in personTwoList)
{
var personTuple = Tuple.Create(person.firstname, person.lastname);
if (!HashTable.ContainsKey(personTuple)) {
HashTable[personTuple] = person;
}
}
var myResult = HashTable.Where(x => x.Value is PersonTwo).Select(x => x.Value).Cast<PersonTwo>().ToList();
The HashTable (Dictionary) simplifies the job of (a) excluding people of type PersonOne from the list, and (b) removing duplicates of person two.
Thirdly, it works in O(N) time, not O(N^2).
First of all I would recommend you to use single class for the Person.
If there are differences then you make parent class as Person and inherit PersonOne and PersonTwo from Person.
For your existing design I will recommend you to use IEnumerable instead of List. Have look
Stopwatch sw = new Stopwatch();
sw.Start();
List<PersonTwo> difference = personTwoList
.GroupBy(x => new { FirstName = x.firstname.ToLower(), LastName = x.lastname.ToLower() })
.Select(x => x.First())
.Where(x => !personOneList.Any(y => y.name.Equals(x.firstname, StringComparison.InvariantCultureIgnoreCase) && y.surname.Equals(x.lastname, StringComparison.InvariantCultureIgnoreCase)))
.ToList();
sw.Stop();
Console.WriteLine("Time elapsed: {0}", sw.ElapsedTicks);//took 83333ms
Stopwatch sw1 = new Stopwatch();
sw1.Start();
IEnumerable<PersonTwo> difference1 = personTwoList
.GroupBy(x => new { FirstName = x.firstname.ToLower(), LastName = x.lastname.ToLower() })
.Select(x => x.First())
.Where(x => !personOneList.Any(y => y.name.Equals(x.firstname, StringComparison.InvariantCultureIgnoreCase) && y.surname.Equals(x.lastname, StringComparison.InvariantCultureIgnoreCase)));
sw1.Stop();
Console.WriteLine("Time elapsed: {0}", sw1.ElapsedTicks);//took 9ms
Console.ReadLine();
Result was based on following generated test data
for (int i = 0; i < 500; i++)
{
personOneList.Add(new PersonOne
{
surname = "a" + i,
name = "b"+ i
});
personTwoList.Add(new PersonTwo
{
lastname = "a" + i,
firstname = "b" + i
});
}
for (int i = 0; i < 100; i++)
{
personTwoList.Add(new PersonTwo
{
lastname = "c" + i,
firstname = "d" + i
});
}
for (int i = 0; i < 100; i++)
{
personTwoList.Add(new PersonTwo
{
lastname = "a" + i,
firstname = "b" + i
});
}
I would like to make a query by using lambda select,
Like below:
public class Foo{
public int Id {get;set;}
public string Name {get;set;}
public string Surname {get;set;}
}
var list = new List<Foo>();
var temp = list.Select(x=> x("Name"),("Surname"));
The property name needs to be sent as a string,
I dont know how to use, I have given it for being a example.
is it possible?
Edit:
Foo list :
1 A B
2 C D
3 E F
4 G H
I don't know type of generic list, I have property name such as "Name", "Surname"
I want to be like below:
Result :
A B
C D
E F
G H
The following code snippet shows 2 cases. One filtering on the list, and another creating a new list of anonymous objects, having just Name and Surname.
List<Foo> list = new List<Foo>();
var newList = list.Select(x=> new {
AnyName1 = x.Name,
AnyName2 = x.Surname
});
var filteredList = list.Select(x => x.Name == "FilteredName" && x.Surname == "FilteredSurname");
var filteredListByLinq = from cust in list
where cust.Name == "Name" && cust.Surname == "Surname"
select cust;
var filteredByUsingReflection = list.Select(c => c.GetType().GetProperty("Name").GetValue(c, null));
Interface
If you have access to the types in question, and if you always want to access the same properties, the best option is to make the types implement the same interface:
public interface INamable
{
string Name { get; }
string Surname { get; }
}
public class Foo : INamable
{
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
}
This will preserve type safety and enable queries like this one:
public void ExtractUsingInterface<T>(IEnumerable<T> list) where T : INamable
{
var names = list.Select(o => new { Name = o.Name, Surname = o.Surname });
foreach (var n in names)
{
Console.WriteLine(n.Name + " " + n.Surname);
}
}
If, for some reason, you can't alter the original type, here are two more options.
Reflection
The first one is reflection. This is Mez's answer, i'll just rephrase it with an anonymous type like in the previous solution (not sure what you need exactly):
public void ExtractUsingReflection<T>(IEnumerable<T> list)
{
var names = list.Select(o => new
{
Name = GetStringValue(o, "Name"),
Surname = GetStringValue(o, "Surname")
});
foreach (var n in names)
{
Console.WriteLine(n.Name + " " + n.Surname);
}
}
private static string GetStringValue<T>(T obj, string propName)
{
return obj.GetType().GetProperty(propName).GetValue(obj, null) as string;
}
Dynamic
The second uses dynamic:
public void ExtractUsingDynamic(IEnumerable list)
{
var dynamicList = list.Cast<dynamic>();
var names = dynamicList.Select(d => new
{
Name = d.Name,
Surname = d.Surname
});
foreach (var n in names)
{
Console.WriteLine(n.Name + " " + n.Surname);
}
}
With that in place, the following code:
IEnumerable<INamable> list = new List<Foo>
{
new Foo() {Id = 1, Name = "FooName1", Surname = "FooSurname1"},
new Foo() {Id = 2, Name = "FooName2", Surname = "FooSurname2"}
};
ExtractUsingInterface(list);
// IEnumerable<object> list... will be fine for both solutions below
ExtractUsingReflection(list);
ExtractUsingDynamic(list);
will produce the expected output:
FooName1 FooSurname1
FooName2 FooSurname2
FooName1 FooSurname1
FooName2 FooSurname2
FooName1 FooSurname1
FooName2 FooSurname2
I'm sure you can fiddle with that and get to what you are trying to achieve.
var temp = list.Select(x => x.Name == "Name" && x.Surname == "Surname");
var temp = list.Select(x => new {Name = x.Name, Surname = x.Surname});
I am very very new to writing c# using delegates and funcs. Literally watched a pluralsite video an hour ago.
I am trying to write a function that will allow me to write a flexible method for building up a Where clause in my mvc application using EF and IQueryable
To try explain I thought I would write a small example of what I am trying to do as a console application
public static void Main(string[] args)
{
var city1 = new ArgsSearch() {Address = "city1"};
var city2 = new ArgsSearch() { Address = "city2" };
var city1Dealers = DummyDealers().Where(GenerateSearchCriteria<CarDealer>(city1)).ToList();
var city2Dealers = DummyDealers().Where(GenerateSearchCriteria<CarDealer>(city2)).ToList();
foreach (var carDealer in city1Dealers)
{
Console.WriteLine(carDealer.Name);
}
Console.WriteLine("_______________________________________");
foreach (var carDealer in city2Dealers)
{
Console.WriteLine(carDealer.Name);
}
Console.WriteLine("_______________________________________");
}
public static List<CarDealer> DummyDealers()
{
return new List<CarDealer>()
{
new CarDealer() {Address = "city1", Id = 1, Name = "name1"},
new CarDealer() {Address = "city1", Id = 2, Name = "name2"},
new CarDealer() {Address = "city2", Id = 3, Name = "name3"},
new CarDealer() {Address = "city2", Id = 4, Name = "name4"}
};
}
public static Func<TSearch, bool> GenerateSearchCriteria<TSearch>(ArgsSearch args) where TSearch : IBaseModel
{
if (this.GetType() == typeof(CarModel))
{
//return
return e => e.Name == args.Name;// && e.Cost == args.Cost;
}
if (GetType() == typeof(CarDealer))
{
return e => e.Name == args.Name;// && e.Address == args.Address;
}
return e => e.Name==args.Name;
}
public class ArgsSearch
{
public string Name { get; set; }
public string Address { get; set; }
public decimal Cost { get; set; }
}
Am I going down the right track? How do I know that TSearch is either CarModel or CarDealer? allowing my custom search values to be applied.
Thanks for any suggestions and any help would be really appreciated!
You need to cast:
(warning: ugly code ahead)
if (typeof(TSearch) == typeof(CarModel))
{
//return
return e => e.Name == args.Name && ((CarModel)(object)e).Cost == args.Cost;
}
if (typeof(TSearch) == typeof(CarDealer))
{
return e => e.Name == args.Name && ((CarDealer)(object)e).Address == args.Address;
}
return e => e.Name==args.Name;