LINQ延迟加载并创建新对象

时间:2017-02-10 16:24:44

标签: c# entity-framework linq

我有几节课,

public class Album
{
    public int AlbumId { get; set; }
    public string Title { get; set; }
    public Genre genre { get; set; }
    public virtual Artist artist { get; set; }
}

public class Artist
{
    public int ArtistId { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Album> albums { get; set; }
}

public class ArtistResponse
{
    public int ArtistId { get; set; }
    public string Name { get; set; }
}

public class AlbumResponse
{
    public int AlbumId { get; set; }
    public string Title { get; set; }
    public Genre genre { get; set; }
    public ArtistResponse artist { get; set; }
}

我尝试使用艺术家下载所有专辑,然后使用AlbumResponse返回。 我有一个LINQ表达式

return ctx.Albums.Include(i => i.artist).Select(i => new AlbumResponse
            {
                AlbumId = i.AlbumId,
                artist = new ArtistResponse {  Name=i.artist.Name, ArtistId=i.artist.ArtistId},
                genre = i.genre,
                Title = i.Title
            }).ToList();

所以我包括&#39;艺术家&#39; by&#34; Include()&#34;然后创建新的AlbumResponse,我在其中创建新的ArtistResponse。不幸的是,它不起作用。它会抛出InvalidOperationException。 &#34; i.artist.ArtistId&#34;是一个null,我不知道为什么,没有ArtistId初始化工作一切正常,只有&#34; Name = i.artist.Name&#34;工作得很好。

如何将ArtistId附加到&#39;艺术家&#39;在&#39; AlbumResponse&#39;? 例外:&#34;演员价值类型&#39; System.Int32&#39;失败,因为具体化值为null。结果类型的通用参数或查询必须使用可空类型&#34; 课程相册和艺术家在数据库中,AlbumId和ArtistId不可为空。 ArtistResponse和AlbumResponse只是&#34;额外&#34;用于在数据库中添加或获取信息的类,所以ArtistId和AlbumId在&#34; * Response&#34;只是整理

3 个答案:

答案 0 :(得分:2)

如果ArtistId导航属性的artist列为Nullable<int>ArtistId类型的ArtistResponse属性类型为{{1你应该检查是否有值返回:

int

这显然只是一个猜测,因为你没有发布你的类型的定义,也没有发现你得到的实际错误信息。

修改

如果您将return ctx.Albums.Include(i => i.artist).Select(i => new AlbumResponse { AlbumId = i.AlbumId, artist = new ArtistResponse { Name = (i.artist != null) ? i.artist.Name : string.Empty, ArtistId = (i.artist != null && i.artist.ArtistId.HasValue) ? artist.ArtistId.Value : 0 }, genre = i.genre, Title = i.Title }).ToList(); 类型的ArtistId属性类型更改为ArtistResponseNullable<int>),该怎么办:

int?

答案 1 :(得分:1)

return ctx.Albums.Include(i => i.artist).Select(i => new AlbumResponse
            {
                AlbumId = i.AlbumId,
                artist = new ArtistResponse {  Name=i.artist.Name, ArtistId=i.artist.ArtistId ?? 0( or Guid.NewGuid() << or this if you decide to use guid type)}, 
                genre = i.genre,
                Title = i.Title
            }).ToList();

如果您不想将其默认为零,则必须为您的艺术家ID指定唯一的数字/键。也许是新的guid?你必须找到一种方法来创建一个独特的int id。

答案 2 :(得分:1)

你可能,我不是说你没有完全的知识,做一个不完整的投射。实体对数据有点奇怪,因为它是一个官方对象,它不会被实现用于门外。 EG:您的位置,选择和其他扩展语法不起作用,因为该对象尚未实现。

您可能希望尝试一些简单的事情:

return ctx.Albums.Include(i => i.artist)

<强> .ToList()

.Select(i => new AlbumResponse
            {
                AlbumId = i.AlbumId,
                artist = new ArtistResponse {  Name= i?.artist?.Name ?? String.Empty, ArtistId=i?.artist?.ArtistId ?? 0},
                genre = i.genre,
                Title = i.Title
            }).ToList();

否则投影可能无法实现其导航属性“艺术家”。 ToList()是穷人快速实现投射的方式,并且基本上说:“.NET现在可以作为合法的对象集合”。您可以使用我认为的“其他扩展”,我相信也是如此。这只是一个猜测,但我知道我已经与EF合作了一段时间,并且在进行加载事件,数学和其他事情时“实现”通常是罪魁祸首。或者它可能正如其他人所说的那样,你只是获得了导航的空引用,它就会爆炸。我做了一些伪代码?条件运算符(如果父元素也是空的话,基本上通过链检查空值而不是吹动)然后是一个合并的空运算符'??'如果这个东西为空,则指定一个默认值。