Используя простой пример ниже, каков наилучший способ вернуть результаты из нескольких таблиц, используя Linq to SQL?
Скажем, у меня есть две таблицы:
Dogs: Name, Age, BreedId
Breeds: BreedId, BreedName
Я хочу вернуть всех собак со своими BreedName
. Я должен заставить всех собак использовать что-то вроде этого без проблем:
public IQueryable<Dog> GetDogs()
{
var db = new DogDataContext(ConnectString);
var result = from d in db.Dogs
join b in db.Breeds on d.BreedId equals b.BreedId
select d;
return result;
}
Но если я хочу собак с породами и попробовать это у меня есть проблемы:
public IQueryable<Dog> GetDogsWithBreedNames()
{
var db = new DogDataContext(ConnectString);
var result = from d in db.Dogs
join b in db.Breeds on d.BreedId equals b.BreedId
select new
{
Name = d.Name,
BreedName = b.BreedName
};
return result;
}
Теперь я понимаю, что компилятор не позволит мне вернуть набор анонимных типов, поскольку он ожидает Dogs, но есть ли способ вернуть это без необходимости создания пользовательского типа? Или я должен создать свой собственный класс DogsWithBreedNames
и указать этот тип в select? Или есть другой способ проще?
c#
linq
linq-to-sql
Джонатан С.
источник
источник
foreach (var cust in query) Console.WriteLine("id = {0}, City = {1}", cust.CustomerID, cust.City);
Ответы:
Я склонен идти по этой схеме:
Это означает, что у вас есть дополнительный класс, но его можно легко и быстро кодировать, легко расширять, использовать повторно и сохранять тип.
источник
Вы можете возвращать анонимные типы, но это действительно не красиво .
В этом случае я думаю, что было бы гораздо лучше создать соответствующий тип. Если он будет использоваться только из типа, содержащего метод, сделайте его вложенным.
Лично я хотел бы, чтобы C # получал «именованные анонимные типы» - то есть такое же поведение, что и анонимные типы, но с именами и объявлениями свойств, но это все.
РЕДАКТИРОВАТЬ: Другие предлагают вернуть собак, а затем получить доступ к названию породы через путь свойства и т. Д. Это совершенно разумный подход, но IME приводит к ситуациям, когда вы выполняете запрос определенным образом из-за данных, которые вы хотите использовать - и эта метаинформация будет потеряна, когда вы просто вернетесь
IEnumerable<Dog>
- запрос может ожидать, что вы будете использовать (скажем),Breed
а неOwner
из-за некоторых параметров загрузки и т. д., но если вы забудете об этом и начнете использовать другие свойства, ваше приложение может работать, но не так эффективно, как вы изначально предполагали. Конечно, я могу говорить о чепухе или чрезмерной оптимизации и т. Д.источник
Просто чтобы добавить ценность в два цента :-) Я недавно узнал, как обрабатывать анонимные объекты. Его можно использовать только при нацеливании на платформу .NET 4 и только при добавлении ссылки на System.Web.dll, но тогда это довольно просто:
Чтобы иметь возможность добавить ссылку на System.Web.dll, вы должны последовать совету rushonerok : убедитесь, что целевой платформой вашего [проекта] является «.NET Framework 4», а не «.NET Framework 4 Client Profile».
источник
Нет, вы не можете вернуть анонимные типы, не пройдя через некоторые хитрости.
Если вы не используете C #, то, что вы будете искать (возвращать несколько данных без конкретного типа), называется Tuple.
Существует множество реализаций кортежей C #, используя показанную здесь , ваш код будет работать следующим образом.
И на сайте вызова:
источник
... select Tuple.Create(d, b)
.Вы могли бы сделать что-то вроде этого:
источник
Вы должны
ToList()
сначала использовать метод, чтобы взять строки из базы данных, а затем выбрать элементы как класс. Попробуй это:Итак, трюк первый
ToList()
. Он сразу делает запрос и получает данные из базы данных. Второй трюк - выбор элементов и использование инициализатора объектов для создания новых объектов с загруженными элементами.Надеюсь это поможет.
источник
В C # 7 теперь вы можете использовать кортежи! ... что избавляет от необходимости создавать класс просто для возврата результата.
Вот пример кода:
Возможно, вам придется установить пакет nuget System.ValueTuple.
источник
Теперь я понимаю, что компилятор не позволит мне вернуть набор анонимных типов, поскольку он ожидает Dogs, но есть ли способ вернуть это без необходимости создания пользовательского типа?
Используйте use object для возврата списка анонимных типов без создания пользовательского типа. Это будет работать без ошибки компилятора (в .net 4.0). Я вернул список клиенту, а затем проанализировал его на JavaScript:
источник
Просто выберите собак, а затем используйте
dog.Breed.BreedName
, это должно работать нормально.Если у вас много собак, используйте DataLoadOptions.LoadWith, чтобы уменьшить количество вызовов БД.
источник
Вы не можете возвращать анонимные типы напрямую, но вы можете зацикливать их с помощью общего метода. Как и большинство методов расширения LINQ. Там нет никакой магии, хотя, похоже, они будут возвращать анонимные типы. Если параметр является анонимным, результат также может быть анонимным.
Ниже приведен пример, основанный на коде из исходного вопроса:
источник
Ну, если вы возвращаете собак, вы должны сделать:
Если вы хотите, чтобы Breed загружался с полной отдачей, а не с отложенной загрузкой, просто используйте соответствующую конструкцию DataLoadOptions .
источник
BreedId
вDog
таблице, очевидно, внешний ключ к соответствующей строке вBreed
таблице. Если ваша база данных настроена правильно, LINQ to SQL должен автоматически создать связь между двумя таблицами. Полученный класс Dog будет иметь свойство Breed, а класс Breed должен иметь коллекцию Dogs. Настроив его таким образом, вы все равно можете вернутьIEnumerable<Dog>
, который является объектом, включающим свойство породы. Единственное предостережение заключается в том, что вам необходимо предварительно загрузить объект породы вместе с объектами собаки в запросе, чтобы к ним можно было получить доступ после удаления контекста данных, и (как предложил другой автор) выполнить метод в коллекции, который вызовет запрос должен быть выполнен немедленно (в данном случае ToArray):Затем тривиально получить доступ к породе для каждой собаки:
источник
Если основная идея состоит в том, чтобы оператор SQL select, отправляемый на сервер базы данных, имел только обязательные поля, а не все поля Entity, тогда вы можете сделать это:
источник
Попробуйте это, чтобы получить динамические данные. Вы можете конвертировать код для списка <>
источник
Если у вас есть настройка отношений в вашей базе данных с внешним ограничением ключа на BreedId, вы уже этого не понимаете?
Теперь я могу позвонить:
И в коде, который вызывает это:
Так что в вашем случае вы будете называть что-то вроде dog.Breed.BreedName - как я уже сказал, это зависит от того, настроена ли ваша база данных с этими отношениями.
Как уже упоминали другие, DataLoadOptions поможет уменьшить количество вызовов базы данных, если это проблема.
источник
Это не совсем отвечает на ваш вопрос, но Google привел меня сюда на основе ключевых слов. Вот как вы можете запросить анонимный тип из списка:
источник