В настоящее время я работаю над требованием, которое использует список и извлекает данные. Но есть изменения, которые мне нужно внести, которых я не получаю.
Теперь у меня есть список элементов, и при выборе пользователя я получаю имена столбцов (случайно), которые являются частью этого списка. Как мне реализовать, потому что во время выполнения я не знаю, сколько имен столбцов я получу.
Ниже приведен пример кода:
class Program
{
static void Main(string[] args)
{
var students = new List<Student>()
{
new Student { Name = "Vijay", Age = 21 , Gender = "M" , Address = "Address_1"},
new Student { Name = "Ajay", Age = 26 , Gender = "M" , Address = "Address_2"},
new Student { Name = "John", Age = 21 , Gender = "M" , Address = "Address_3"},
new Student { Name = "Rob", Age = 42 , Gender = "M" , Address = "Address_4"},
new Student { Name = "Kohli", Age = 32 , Gender = "M" , Address = "Address_5"}
};
var result = students.Select(x => x.Name);
// I get result with Name column. That's fine.
}
}
public class Student
{
public string Name;
public int Age;
public string Gender;
public string Address;
}
Приведенный выше код является лишь примером того, что я пытаюсь объяснить. Так как students.Select(x => x.Name); даст мне результат, который имеет список Names. Но иногда я могу получать имена столбцов, разделенных запятыми.
например Name, Gender или Age, Gender или Name, Address или Address или все имена столбцов.
Expected results:
// When user sends Name & Gender as selected columns
Name, Gender
vijay 26
Ajay 21
Rob 42
...
// When user sends only Address as selected columns
Address
Address_1
Address_2
....
Может ли кто-нибудь помочь мне, как мне создать среду выполнения select, используя доступный список.
заранее спасибо
Не могли бы вы привести пример ожидаемых данных (для сложного сценария)
обновил ожидаемый результат в вопросе
Это хрупкий сценарий, реальная жизнь так не работает. Вы должны определить конечную точку для каждого запроса, такого как GetByAddress, GetByNameAndGender и т. д. Если вы все еще хотите сделать, как вы упомянули, сначала вам нужно проанализировать запрос, а затем проанализировать его, а затем с помощью оператора switch или if применить тематический запрос (из-за этого он хрупкий)
Этот вопрос, похоже, не имеет ничего общего с EF, но что касается Linq, вы можете использовать что-то вроде этого: stackoverflow.com/questions/24732724/… Это не будет работать с EF, так как разрешить до SQL. Для EF вам нужно будет использовать условную логику, чтобы решить, какой .Select() оператор вы хотите применить к запросу.
Как вы используете результаты? Вернется ли он к пользовательскому интерфейсу... как Json?





Я действительно сделал это некоторое время назад для веб-API. По сути, вы можете использовать Newtonsoft.Json для сериализации вашего типа, сохраняя при этом только те поля\свойства, которые вам нужны.
Во-первых, вам понадобится пользовательский ContractResolver:
public class SelectiveContractResolver : DefaultContractResolver
{
private readonly HashSet<string> properties;
public SelectiveContractResolver(HashSet<string> selectedProperties)
{
properties = selectedProperties;
}
protected override JsonProperty CreateProperty
(
MemberInfo member,
MemberSerialization memberSerialization
)
{
var property = base.CreateProperty(member, memberSerialization);
property.ShouldSerialize = _ =>
properties
.Contains(
$"{member.ReflectedType.FullName.ToString()}.{member.Name}"
.ToLower());
return property;
}
}
Здесь я специально формирую свои строки, такие как «[полный путь идет здесь].Student.Name» или «[такой же здесь].Student.Gender» и проверяю, было ли выбрано свойство. Это может быть полезно, если вы собираетесь сериализовать сложные типы и вам нужно будет передавать выборки для разных типов вашему Resolver.
Второе, что нужно сделать, и это чисто для оптимизации, создать фабрику, которая кэширует ваши преобразователи, чтобы вам не приходилось каждый раз их пересобирать:
public class SelectiveContractResolverFactory
{
private ConcurrentDictionary<HashSet<string>, IContractResolver>
cachedResolvers;
public SelectiveContractResolverFactory()
{
cachedResolvers =
new ConcurrentDictionary<HashSet<string>, IContractResolver>
(HashSet<string>.CreateSetComparer());
}
public IContractResolver GetResolver
(
IEnumerable<string> selectedProperties
)
{
var selectedSet = selectedProperties.ToHashSet();
if (cachedResolvers.ContainsKey(selectedSet))
return cachedResolvers[selectedSet];
var newResolver = new SelectiveContractResolver(selectedSet);
cachedResolvers[selectedSet] = newResolver;
return newResolver;
}
}
Наконец, давайте применим это к объекту:
var student = new Student { Name = "Vijay", Age = 21 , Gender = "M" , Address = "Address_1"};
var selectedProps = new List<string> {"Student.Name","Student.Age"};
// Obviously, this should be injected as a singleton:
var resolverFactory = new SelectiveContractResolverFactory();
var resolver = resolverFactory.GetResolver(selectedProps);
var selectedResult = JsonConvert.SerializeObject
(
student,
Formatting.None,
new JsonSerializerSettings
{
ContractResolver = resolver
}
);
И вот так вы получаете аккуратный json-объект с нужными вам свойствами.
Но если вам нужно получить из этого настоящий объект C#, вы можете десериализовать его в ExpandoObject, используя ExpandoObjectConverter:
dynamic filteredStudent = JsonConvert
.DeserializeObject<ExpandoObject>
(
selectedResult,
new ExpandoObjectConverter()
);
Хотя, судя по формулировке вопроса, я чувствую, что вы собираетесь возвращать эти данные из своего рода API, поэтому json уже идеально подходит для этого.
Dynamic Linq может вам помочь.
using System.Linq.Dynamic.Core;
var values = new List<string> { "Age", "Gender" };
var columns = "new {" + string.Join(",", values) + "}";
var result = students.AsQueryable().Select(columns);
foreach (var x in result)
Console.WriteLine(x);
Выход:
{ Age = 21, Gender = M }
{ Age = 26, Gender = M }
{ Age = 21, Gender = M }
{ Age = 42, Gender = M }
{ Age = 32, Gender = M }
Имейте в виду, что вы получаете анонимный тип. А как вы будете с ним работать дальше — это еще вопрос.
Мне нужно экспортировать эти данные в excel..!! Даже сейчас worksheet.Cells["A1"].LoadFromCollection(resultList, true) где я получаю исключение
Я должен отметить, что этот подход смехотворно медленный. Всего 1000 итераций по этому исходному списку из 5 студентов занимают почти 2 полных секунды на приличной машине. При 100 тыс. итераций мне пришлось ждать 1 минуту 41 секунду. Если я не пропускаю какую-то оптимизацию, ее не следует использовать ни в одной системе, которая ожидает приличную нагрузку. Для сравнения, мой подход занимает около 2,131 секунды со 100 000 итераций.
Я бы порекомендовал переосмыслить, как вы это делаете... если вам случайным образом нужны значения из объекта, вы должны возвращать объект, а затем использовать любое значение, которое вам нужно, на стороне клиента или в интерфейсе.