Вернуть результаты анонимного типа? - PullRequest
181 голосов
/ 11 февраля 2009

Используя простой пример, приведенный ниже, каков наилучший способ вернуть результаты из нескольких таблиц с использованием 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? Или есть другой, более простой способ?

Ответы [ 15 ]

0 голосов
/ 22 ноября 2018

Попробуйте, чтобы получить динамические данные. Вы можете конвертировать код для списка <>

public object 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.FirstOrDefault();
}

dynamic dogInfo=GetDogsWithBreedNames();
var name = dogInfo.GetType().GetProperty("Name").GetValue(dogInfo, null);
var breedName = dogInfo.GetType().GetProperty("BreedName").GetValue(dogInfo, null);
0 голосов
/ 04 июня 2016

Если основная идея состоит в том, чтобы оператор выбора SQL, отправляемый на сервер базы данных, имел только обязательные поля, а не все поля сущности, тогда вы можете сделать это:

public class Class1
{
    public IList<Car> getCarsByProjectionOnSmallNumberOfProperties()
    {

        try
        {
            //Get the SQL Context:
            CompanyPossessionsDAL.POCOContext.CompanyPossessionsContext dbContext 
                = new CompanyPossessionsDAL.POCOContext.CompanyPossessionsContext();

            //Specify the Context of your main entity e.g. Car:
            var oDBQuery = dbContext.Set<Car>();

            //Project on some of its fields, so the created select statment that is
            // sent to the database server, will have only the required fields By making a new anonymouse type
            var queryProjectedOnSmallSetOfProperties 
                = from x in oDBQuery
                    select new
                    {
                        x.carNo,
                        x.eName,
                        x.aName
                    };

            //Convert the anonymouse type back to the main entity e.g. Car
            var queryConvertAnonymousToOriginal 
                = from x in queryProjectedOnSmallSetOfProperties
                    select new Car
                    {
                        carNo = x.carNo,
                        eName = x.eName,
                        aName = x.aName
                    };

            //return the IList<Car> that is wanted
            var lst = queryConvertAnonymousToOriginal.ToList();
            return lst;

        }
        catch (Exception ex)
        {
            System.Diagnostics.Debug.WriteLine(ex.ToString());
            throw;
        }
    }
}
0 голосов
/ 04 декабря 2013

BreedId в таблице Dog, очевидно, является внешним ключом для соответствующей строки в таблице Breed. Если ваша база данных настроена правильно, LINQ to SQL должен автоматически создать связь между двумя таблицами. Полученный класс Dog будет иметь свойство Breed, а класс Breed должен иметь коллекцию Dogs. Настроив его таким образом, вы все равно можете вернуть IEnumerable<Dog>, который является объектом, включающим свойство породы. Единственное предостережение заключается в том, что вам необходимо предварительно загрузить объект породы вместе с объектами собаки в запросе, чтобы к ним можно было получить доступ после удаления контекста данных, и (как предложил другой автор) выполнить метод в коллекции, который вызовет запрос должен быть выполнен немедленно (в данном случае ToArray):

public IEnumerable<Dog> GetDogs()
{
    using (var db = new DogDataContext(ConnectString))
    {
        db.LoadOptions.LoadWith<Dog>(i => i.Breed);
        return db.Dogs.ToArray();
    }

}

Затем тривиально получить доступ к породе для каждой собаки:

foreach (var dog in GetDogs())
{
    Console.WriteLine("Dog's Name: {0}", dog.Name);
    Console.WriteLine("Dog's Breed: {0}", dog.Breed.Name);        
}
0 голосов
/ 11 февраля 2009

Если у вас в вашей базе данных есть настройки взаимоотношений с внешним ограничением ключа в BreedId, вы уже этого не понимаете?

DBML relationship mapping

Так что теперь я могу позвонить:

internal Album GetAlbum(int albumId)
{
    return Albums.SingleOrDefault(a => a.AlbumID == albumId);
}

И в коде, который вызывает это:

var album = GetAlbum(1);

foreach (Photo photo in album.Photos)
{
    [...]
}

Так что в вашем случае вы будете называть что-то вроде dog.Breed.BreedName - как я уже сказал, это зависит от того, настроена ли ваша база данных с этими отношениями.

Как уже упоминали другие, DataLoadOptions поможет уменьшить количество вызовов базы данных, если это проблема.

0 голосов
/ 11 февраля 2009

Ну, если вы возвращаете Собак, вы должны сделать:

public IQueryable<Dog> GetDogsWithBreedNames()
{
    var db = new DogDataContext(ConnectString);
    return from d in db.Dogs
           join b in db.Breeds on d.BreedId equals b.BreedId
           select d;
}

Если вы хотите, чтобы Breed загружался с нетерпением и не загружался лениво, просто используйте соответствующую конструкцию DataLoadOptions .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...