EF core + Automapper ID-only相关实体集合,怎么样?
EF core + Automapper ID-only related entity collection, how?
我有一个简单的问题 - 我希望 RESTful 端点之一服务于资源 DTO(自动映射),其相关资源仅作为其 ID。但是,如果不加载整个(和沉重的)相关实体,似乎没有任何方法可以实现它。考虑以下(数据库优先)示例模型:
public partial class Blog
{
public int Id { get; set; }
public string Url { get; set; }
public virtual ICollection<Post> Posts { get; set; }
}
public partial class Post // some heavy entity
{
public int Id { get; set; }
public string Content { get; set; }
// other properties
}
及其对应的DTO
// api/v1/blogs serves collection of following type
public class BlogSlimDto
{
public int Id { get; set; }
public string Url { get; set; }
public int[] PostIds { get; set; }
}
一个简单的解决方案是从数据库中获取所有相关的 Post
并丢弃除 ID 之外的所有数据,但这可能效率低下甚至不可行,具体取决于相关的 Post
实体大小:
var result = ctx.Blogs.Include(blog => blog.Posts) //fecth everything and discard it on next line
.Select(blog => _mapper.Map<BlogSlimDto>(blog));
// simply use a profile that discards Posts but keeps their Ids, e.g.
// .forMember(dto => dto.PostIds, opt => opt.MapFrom(db.Posts.Select(p => p.Id)))
提供了一个使用匿名类型的解决方案,但是这在 Automapper 中根本不能很好地发挥作用:
var result = ctx.Blogs.Select(blog => new {
blog.Id,
blog.Url,
PostIds = blog.Posts.Select(b => b.Id),
}).Select(ablog => _mapper.Map<BlogSlimDto>(ablog)); //throws, no mapping and such mapping cannot be defined
上面的代码将在运行时抛出异常,因为没有定义 Automapper 映射。更糟糕的是,它无法定义,因为 Automapper 中有 no support for anonymous types。此外,具有一对一 'manual' 属性 分配的解决方案往往难以维护。
是否有替代解决方案允许 EF 查询而不获取整个相关实体,同时允许将结果自动映射到 BlogSlimDto
?
您可以使用可查询的扩展:
https://docs.automapper.org/en/stable/Queryable-Extensions.html
var configuration = new MapperConfiguration(cfg =>
cfg.CreateMap<OrderLine, OrderLineDTO>()
.ForMember(dto => dto.Item, conf => conf.MapFrom(ol => ol.Item.Name)));
public List<OrderLineDTO> GetLinesForOrder(int orderId)
{
using (var context = new orderEntities())
{
return context.OrderLines.Where(ol => ol.OrderId == orderId)
.ProjectTo<OrderLineDTO>().ToList();
}
}
用您的 Post 和博客
替换 Item 和 OrderLine
我有一个简单的问题 - 我希望 RESTful 端点之一服务于资源 DTO(自动映射),其相关资源仅作为其 ID。但是,如果不加载整个(和沉重的)相关实体,似乎没有任何方法可以实现它。考虑以下(数据库优先)示例模型:
public partial class Blog
{
public int Id { get; set; }
public string Url { get; set; }
public virtual ICollection<Post> Posts { get; set; }
}
public partial class Post // some heavy entity
{
public int Id { get; set; }
public string Content { get; set; }
// other properties
}
及其对应的DTO
// api/v1/blogs serves collection of following type
public class BlogSlimDto
{
public int Id { get; set; }
public string Url { get; set; }
public int[] PostIds { get; set; }
}
一个简单的解决方案是从数据库中获取所有相关的 Post
并丢弃除 ID 之外的所有数据,但这可能效率低下甚至不可行,具体取决于相关的 Post
实体大小:
var result = ctx.Blogs.Include(blog => blog.Posts) //fecth everything and discard it on next line
.Select(blog => _mapper.Map<BlogSlimDto>(blog));
// simply use a profile that discards Posts but keeps their Ids, e.g.
// .forMember(dto => dto.PostIds, opt => opt.MapFrom(db.Posts.Select(p => p.Id)))
var result = ctx.Blogs.Select(blog => new {
blog.Id,
blog.Url,
PostIds = blog.Posts.Select(b => b.Id),
}).Select(ablog => _mapper.Map<BlogSlimDto>(ablog)); //throws, no mapping and such mapping cannot be defined
上面的代码将在运行时抛出异常,因为没有定义 Automapper 映射。更糟糕的是,它无法定义,因为 Automapper 中有 no support for anonymous types。此外,具有一对一 'manual' 属性 分配的解决方案往往难以维护。
是否有替代解决方案允许 EF 查询而不获取整个相关实体,同时允许将结果自动映射到 BlogSlimDto
?
您可以使用可查询的扩展: https://docs.automapper.org/en/stable/Queryable-Extensions.html
var configuration = new MapperConfiguration(cfg =>
cfg.CreateMap<OrderLine, OrderLineDTO>()
.ForMember(dto => dto.Item, conf => conf.MapFrom(ol => ol.Item.Name)));
public List<OrderLineDTO> GetLinesForOrder(int orderId)
{
using (var context = new orderEntities())
{
return context.OrderLines.Where(ol => ol.OrderId == orderId)
.ProjectTo<OrderLineDTO>().ToList();
}
}
用您的 Post 和博客
替换 Item 和 OrderLine