繁体   English   中英

使用具有Collection属性的LINQ to Entities的最佳方法

[英]Best way to use LINQ to Entities with a Collection Property

假设我有以下型号:

城市和训练站

正如您所看到的,每个城市都有一个或多个火车站。

我有以下类型:

public class CityDTO
{
    public string CityName { get; set; }
    public string StateName { get; set; }
    public List<string> Trainstations { get; set; }
}

现在关于LINQ的很酷的事情是我可以查询实体框架并返回我的类型的新集合:

    public List<CityDTO> GetCities()
    {
        using (var db = new CityDataContext())
        {

            var cities = db.Cities;
            var trainstations = db.TrainStations;

            var query =
            (from city in cities
             select new CityDTO
             {
                 CityName = city.Name,
                 StateName = city.State

             }).ToList();

            return query;
        }
    }

问题是:我是否可以在同一LINQ查询中返回火车站名称的集合以添加到我的CityDTO类?

   public List<CityDTO> GetCities()
    {
        using (var db = new CityDataContext())
        {

            var cities = db.Cities;
            var trainstations = db.TrainStations;

            var query =
            (from city in cities
             join trainstation in trainstations
             on city.CityId
             equals trainstation.CityId into orderGroup
             select new CityDTO
             {
                 CityName = city.Name,
                 StateName = city.State
                 //assign List<string> of trainstation names to CityDTO.Trainstations

             }).ToList();

            return query;
        }
    }

上面加入的另一个问题是它会多次返回相同的城市名称(对于每个火车站),我只想要每个城市有一个CityDTO实例。

最好用两个LINQ语句完成吗? 一个获得一个新的城市列表,第二个获得每个城市的火车站列表?

@ haim770,你的回答帮助我走上正轨。 作为一个利益问题,我不得不改变另外两件事。

当我刚添加Select投影机时,出现以下运行时错误

在此输入图像描述

所以Select期望预计的类型是IEnumerable,所以我可以做到这一点,一切都很酷:

public class CityDTO
{
    public string CityName { get; set; }
    public string StateName { get; set; }
    public IEnumerable<string> Trainstations { get; set; } //changed from List<> to IEnumerable<> 
}

现在这很好用:

    public List<CityDTO> GetCities()
    {
        using (var db = new CitysDataEntities())
        {
            var cities = db.Cities;

            var query =
            (from city in cities
             select new CityDTO
                 {
                    CityName = city.Name,
                    Trainstations = city.TrainStations.Select(ts => ts.Name)  //now this works

                 }).ToList();

            return query;
        }
    }

但是,在进一步阅读之后,我决定使用IQueryable,它也有Select方法。

原因是IQueryable.Select在System.Linq下,而IEnumerable.Select在System.Collections命名空间中。 这很重要,因为IQueryable.Select已经过优化,可以在服务器上执行所有过滤器并仅将结果返回给客户端,而IEnumerable.Select在过滤之前首先将对象加载到客户端。

IEnumerable Vs IQueryable

结果是这样的

public class CityDTO
{
    public string CityName { get; set; }
    public string StateName { get; set; }
    public IQueryable<string> Trainstations { get; set; } // changed to IQueryable
}

    public List<CityDTO> GetCities()
    {
        using (var db = new CitysDataEntities())
        {
            var cities = db.Cities;

            var query =
            (from city in cities
             select new CityDTO
                 {
                    CityName = city.Name,
                     Trainstations = city.TrainStations.Select(ts => ts.Name).AsQueryable() // return AsQueryable

                 }).ToList();

            return query;
        }
    }

现在,当我添加过滤器时,它们将应用于服务器端。

MSDN - Queryable.Select

MSDN - Enumerable.Select

这里的Join操作是隐含的,因为从CityTrainStations有一个导航属性,因此EF将能够自动为您检索工作站:

(from city in cities
 select new CityDTO
     {
     CityName = city.Name,
     StateName = city.State,
     Trainstations = city.TrainStations.Select(ts => ts.Name).ToList()
     })

以上是使用Select()将列车站列表基于Name属性投影string列表中。

请参阅MSDN

使用AutoMapper将集合属性投影到IList。

Queryable.ProjectTo<UserListDto>().ToArray();

实体

public class User
{
    public string Name { get; set; }

    public virtual ICollection<UserRole> Roles { get; set; }  
}

DTO

[AutoMapFrom(typeof(User))]
public class UserListDto
{
    public string Name { get; set; }

    public IList<UserRoleOutput> Roles { get; set; }

    [AutoMapFrom(typeof(UserRole))]
    public class UserRoleOutput
    {
        public int RoleId { get; set; }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM