【问题标题】:Linq Lamda expression to select multiple columns from entity class and its navigation property用于从实体类及其导航属性中选择多个列的 Linq Lambda 表达式
【发布时间】: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>();

                }
            }

【问题讨论】:

    标签: c# entity-framework linq linq-to-entities entity-framework-5


    【解决方案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 }));
      • 我发布了第二个答案,希望能解决您的问题。
      猜你喜欢
      • 1970-01-01
      • 2016-04-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-25
      • 2010-12-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多