我们说我有以下型号:
正如您所看到的,每个城市都有一个或多个火车站。
我有以下类型:
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语句吗?一个是获取新的城市列表,第二个是获取每个城市的火车站列表?
答案 0 :(得分:4)
@ 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会在过滤之前将对象加载到客户端 first 。
结果是这个
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;
}
}
现在,当我添加过滤器时,它们将应用于服务器端。
答案 1 :(得分:2)
这里的Join
操作是隐式的,因为有City
到TrainStations
的导航属性,因此EF可以自动为您检索电台:
(from city in cities
select new CityDTO
{
CityName = city.Name,
StateName = city.State,
Trainstations = city.TrainStations.Select(ts => ts.Name).ToList()
})
以上是基于Select()
属性将string
项目列车站列为Name
列表。
请参阅MSDN
答案 2 :(得分:0)
使用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; }
}
}