Преобразование анонимного типа в новый тип кортежей С# 7
Появилась новая версия С# с полезной новой функцией Типы Tuple:
public IQueryable<T> Query<T>();
public (int id, string name) GetSomeInfo() {
var obj = Query<SomeType>()
.Select(o => new {
id = o.Id,
name = o.Name,
})
.First();
return (id: obj.id, name: obj.name);
}
Есть ли способ преобразовать объект анонимного типа obj в кортеж, который я хочу вернуть без свойства сопоставления по свойству (при условии, что имена свойств совпадают)?
Контекст находится в ORM, мой объект SomeType имеет много других свойств и сопоставляется с таблицей с большим количеством столбцов. Я хочу сделать запрос, который приносит только ID и NAME, поэтому мне нужно преобразовать анонимный тип в кортеж, или мне нужно, чтобы поставщик ORM Linq знал, как понимать кортеж, и помещал связанные с ним столбцы в предложение SQL select.
Ответы
Ответ 1
Короткий ответ - нет, в текущей форме С# 7 нет встроенного способа выполнения ваших целей дословно, так как вы хотите выполнить:
- Linq к лицам
- Отображение подмножества столбцов
- Предотвращение свойства путем сопоставления свойств из пользовательского или анонимного типа в кортеж С# 7 путем прямого сопоставления с кортежем С# 7.
Поскольку Query<SomeType>
предоставляет IQueryable
, в дерево выражений .Select(x => new {})
должен быть сделан любой вид проекции.
Для добавления этой поддержки существует open roslyn issue, но она еще не существует.
В результате, пока эта поддержка не будет добавлена, вы можете вручную сопоставить анонимный тип с кортежем или вернуть всю запись и сопоставить результат с кортежем напрямую, чтобы избежать двух сопоставлений, но это явно неэффективно.
В то время как это ограничение в настоящее время запекается в Linq-to-Entities из-за отсутствия поддержки и невозможности использования параметризованных конструкторов в проекции .Select()
, как Linq-to-NHibernate, так и Linq-to-Sql позволяют взломать в виде создания System.Tuple
в проекции .Select()
, а затем вернуть значение ValueTuple с помощью . Метод расширения ToValueTuple()
public IQueryable<T> Query<T>();
public (int id, string name) GetSomeInfo() {
var obj = Query<SomeType>()
.Select(o => new System.Tuple<int, string>(o.Id, o.Name))
.First();
return obj.ToValueTuple();
}
Так как System.Tuple можно сопоставить с выражением, вы можете вернуть подмножество данных из своей таблицы и разрешить фреймворку обрабатывать сопоставление с вашим кортежем С# 7. Затем вы можете деконструировать аргументы с помощью любого соглашения об именах, которое вы выберете:
(int id, string customName) info = GetSomeInfo();
Console.Write(info.customName);
Ответ 2
Конечно, создав кортеж из выражения LINQ:
public (int id, string name) GetSomeInfo() {
var obj = Query<SomeType>()
.Select(o => (o.Id,o.Name))
.First();
return obj;
}
В соответствии с другим ответом относительно кортежей, предшествующих С# 7, вы можете использовать AsEnumerable()
, чтобы предотвратить перезагрузку EF. (У меня мало опыта работы с EF, но это должно делать:)
public (int id, string name) GetSomeInfo() {
var obj = Query<SomeType>()
.AsEnumerable()
.Select(o => (o.Id,o.Name))
.First();
return obj;
}
Ответ 3
Хотя литералы кортежей в настоящее время не поддерживаются в деревьях выражений, это не означает, что тип ValueTuple
не поддерживается. Просто создайте это явно.
public (int id, string name) GetSomeInfo() =>
Query<SomeType>()
.Select(o => ValueTuple.Create(o.Id, o.Name))
.First();
Ответ 4
Примечание для тех, кто работает в более низкой версии .NET: если вы используете более низкую версию .NET, чем 4.7.2 или .NET Core, вы должны использовать Nuget Package Manager для установки System.ValueTuple в ваш проект.
Затем, вот пример получения кортежа из запроса Linq to SQL:
var myListOfTuples = (from record1 in myTable.Query()
join record2 in myTable2.Query() on record1.Id = record2.someForeignKey
select new {record1, record2}).AsEnumerable()
.select(o => (o.record1, o.record2))
.ToList()
Это бежало для меня, однако, после регистрации, я получил сбой сборки... читать дальше.
Для еще большего удовольствия и игр у меня, к сожалению, по какой-то причине была более ранняя версия С# на моем сервере сборки. Поэтому мне пришлось вернуться назад, потому что он не распознал новый формат кортежа в строке .select(o => (o.record1, o.record2)) (в частности, что это будет кортеж из-за скобок вокруг o. record1 и o.record2). Итак, я должен был вернуться назад и немного больше узнать об этом:
var myListOfAnonymousObjects = (from record1 in myTable.Query()
join record2 in myTable2.Query() on record1.Id = record2.someForeignKey
select new {record1, record2}).ToList()
var myTuples = new List<Tuple<Record1sClass, Record2sClass>>();
foreach (var pair in myListOfAnonymousObjects)
{
myTuples.Add(pair.record1, pair.record2);
}
return myTuples;
Ответ 5
public IList<(int DictionaryId, string CompanyId)> All(string DictionaryType)
{
var result = testEntities.dictionary.Where(p => p.Catalog == DictionaryType).ToList();
var resultTuple = result.Select(p => (DictionaryId: p.ID, CompanyId: p.CompanyId));
return resultTuple.ToList();
}
Этот метод вы можете назвать свой элемент кортежа в linq select