用于从实体类及其导航属性中选择多个列的 Linq Lambda 表达式
Posted
技术标签:
【中文标题】用于从实体类及其导航属性中选择多个列的 Linq Lambda 表达式【英文标题】:Linq Lamda expression to select multiple columns from entity class and its navigation property 【发布时间】:2018-08-22 02:39:30 【问题描述】:我正在使用存储库模式并具有以下实体类和 DTO 类。在我的服务中,我正在实现一个接口来获取所有类别(类型)GetAlbumsInAllCategories 中的专辑(专辑名称)。我只需要在函数GetAlbumsInAllCategories 中的linq lamda 中按这些列分组返回这些字段-abbumcategory.type、song.album、song.albumcover。下面 GetAlbumsInAllCategories 中的 linq lamda 表达式在下面一行的 Select 关键字处给出了这个错误。
return albums.ToList().Select(Mapper.Map<AlbumsByCategory, AlbumsByCategoryDTO>);
Error at select keyword
错误是因为我只从存储库类 AlbumRepository 和导航属性歌曲中选择了几列。而且我不想为少数选定的列创建新的 DTO 类,有没有办法在不为少数选定的列创建新的 DTO 而是使用现有的 AlbumsByCategory 和导航歌曲的情况下做到这一点?
T-SQL 翻译
select
ab.[type],s.Album,s.[AlbumCover]
from
[dbo].[AlbumsByCategory] ab
join [dbo].[Songs] s on s.Id=ab.SongId
where ab.Archived=0 and ab.ShowByAlbums=1
group by
ab.[type],s.Album,s.[AlbumCover]
结果 Result of SQL query above
专辑分类
public partial class AlbumsByCategory
public int Album_Song_Id get; set;
public string Type get; set;
public int SongId get; set;
public bool ShowByAlbums get; set;
public Nullable<System.DateTimeOffset> FromDate get; set;
public Nullable<System.DateTimeOffset> ToDate get; set;
public bool Archived get; set;
public virtual Song Song get; set;
歌曲
public partial class Song
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Song()
this.Favorites = new HashSet<Favorite>();
this.HitMiscSongs = new HashSet<HitMiscSong>();
this.PlayListSongs = new HashSet<PlayListSong>();
this.AlbumsByCategories = new HashSet<AlbumsByCategory>();
public int Id get; set;
public string Title get; set;
public string Artist get; set;
public string Genre get; set;
public string AlbumCover get; set;
public string Album get; set;
public string ContentType get; set;
public string FilePath get; set;
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Favorite> Favorites get; set;
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<HitMiscSong> HitMiscSongs get; set;
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<PlayListSong> PlayListSongs get; set;
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<AlbumsByCategory> AlbumsByCategories get; set;
DTO 类
public class AlbumsByCategoryDTO
public int Album_Song_Id get; set;
public string Type get; set;
public int SongId get; set;
public bool ShowByAlbums get; set;
public Nullable<System.DateTimeOffset> FromDate get; set;
public Nullable<System.DateTimeOffset> ToDate get; set;
public bool Archived get; set;
public virtual SongDTO Song get; set;
public class SongEntity
public int Id get; set;
public string Title get; set;
public string Artist get; set;
public string Genre get; set;
public string AlbumCover get; set;
public string Album get; set;
public string ContentType get; set;
public string FilePath get; set;
public virtual ICollection<FavoriteEntity> Favorites get; set;
public virtual ICollection<PlayListSongEntity> PlayListSongs get; set;
GetAlbumsInAllCategories 中上述 TSQL 的 Linq Lamda
public class AlbumServices : IAlbumServices
private readonly UnitOfWork _unitOfWork;
/// <summary>
/// Public constructor.
/// </summary>
public AlbumServices(UnitOfWork unitOfWork)
_unitOfWork = unitOfWork;
public IEnumerable<AlbumsByCategoryEntity> GetAlbumsInAllCategories()
var albums = _unitOfWork.AlbumRepository.GetAll()
.Where(y => y.Archived == false && y.ShowByAlbums == true)
.GroupBy(y => new y.Type, y.Song.Album, y.Song.AlbumCover )
.ToList()
.SelectMany(x => x.Select(y => new y.Type, y.Song.Album, y.Song.AlbumCover ));
if (albums.Any())
return albums.ToList().Select(Mapper.Map<AlbumsByCategory, AlbumsByCategoryDTO>);
return Enumerable.Empty<AlbumsByCategoryDTO>();
【问题讨论】:
【参考方案1】:听起来您正试图从初始查询中选择几个字段,然后只返回其中的一些。如果你不想创建一个特殊的类(我们称之为模型),那么你就会被匿名类型困住。如果您计划将结果传递给其他函数或进一步查询它,这很难使用。这是一个 linq 查询示例,其中特定字段从多个表中选择为匿名类型。
var seg = context.TaskSegments
.Where(s => s.SegmentID == ID)
.Select(s => new
SegmentID = s.SegmentID,
TaskID = s.TaskID,
TaskType = s.Task.Type,
DisplayAs = s.Task.DisplayAs,
Value = s.Value,
CompletedOn = s.CompletedOn,
ModifiedBy = s.ModifiedBy,
ModifiedOn = s.ModifiedOn,
RequiresCompleteDate = s.Task.RequiresCompleteDate,
AllowAttachments = s.Task.AllowAttachments,
UseYesNoCompletion = s.Task.UseYesNoCompletion,
DisplayXWhenNotCompleted = s.Task.DisplayXWhenNotCompleted,
Responsible = s.Task.Responsible,
Secondary = s.Task.ResponsibleSecondary,
Confirmation = s.Task.Confirmation
)
.FirstOrDefault();
【讨论】:
【参考方案2】:您尝试执行的操作有点令人困惑,但您的选择似乎缺少函数运算符 (s =>),并且可能缺少用于创建返回对象的新关键字。
Select(s => new Mapper.Map<AlbumsByCategory, AlbumsByCategoryDTO>)
其次,我从不使用在您使用 DTO 工具时创建的映射器对象。我为我的所有 DTO 对象创建了一个基类,并有一个构造函数,它接受一个实体并为我复制所有内容。我还具有返回 DTO 的功能,因此它是一条 2 路街道。它只会复制存在的属性,因此您可以拥有部分对象,并且如果某些属性不存在,它也不会失败。
public class DTOBase
public DTOBase()
public DTOBase(Object Entity)
if (Entity == null) return;
Type tObjFrom = Entity.GetType();
Type tObjTo = this.GetType();
var listPropObj1 = tObjFrom.GetProperties().Where(p => p.GetValue(Entity) != null).ToList();
foreach (var item in listPropObj1)
if (tObjTo.GetProperty(item.Name) != null)
tObjTo.GetProperty(item.Name).SetValue(this, item.GetValue(Entity));
public void MapToEntity(object Entity)
if (Entity == null) return;
Type tObjTo = Entity.GetType();
Type tObjFrom = this.GetType();
var listPropObj1 = tObjFrom.GetProperties().ToList();
foreach (var item in listPropObj1)
if (tObjTo.GetProperty(item.Name) != null)
//if (item.GetValue(this) != null)
tObjTo.GetProperty(item.Name).SetValue(Entity, item.GetValue(this));
所以当我从数据库运行我的 Linq 时,我只是动态创建 DTO。
.ToList() .Select(s => new EmployeeDTO(s))
如果您想从 DTO 回到实体,请执行此操作...
EmployeeDTO.MapToEntity(Employee)
【讨论】:
我得到的错误很简单,没有与我在下面的代码中选择的少数字段匹配的类。不想为查询返回的少数字段创建新类。有没有使用现有类只返回几列的方法? var albums = _unitOfWork.AlbumRepository.GetAll() .Where(y => y.Archived == false && y.ShowByAlbums == true) .GroupBy(y => new y.Type, y.Song.Album, y. Song.AlbumCover ) .ToList() .SelectMany(x => x.Select(y => new y.Type, y.Song.Album, y.Song.AlbumCover )); 我发布了第二个答案,希望能解决您的问题。以上是关于用于从实体类及其导航属性中选择多个列的 Linq Lambda 表达式的主要内容,如果未能解决你的问题,请参考以下文章
sql 用于选择Magento实体EAV属性及其值的一系列查询。这里有很多联盟......
在LINQ to Entities中不支持指定的类型成员'x'。只支持初始化器实体成员和实体导航属性。