我有一个List<Category>
public partial class Category
{
public int CategoryId { get; set; }
public string? Name { get; set; }
public int? ImageId { get; set; }
public virtual ProductImage? Image { get;
set; }
public virtual ICollection<Product> Products { get; } = new List<Product>();
}
,我想用一个linq表达式创建一个List<(string, Image)>
。我该怎么做呢?
使用多个指令进行操作将看起来像这样:
List<Category> CategoriesWithImages = Context.Categories.Include(c => c.Image).ToList();
List<(string, Image)> values = new List<(string, Image)>();
CategoriesWithImages.ForEach(c => values.Add((c.Name, Image.FromStream(new MemoryStream(c.Image.Image)))));
有更好的方法吗?
编辑:不幸的是,我不得不使用Include()方法从另一个表加载图像你可以这样做:
List<(string, Image)> values = CategoriesWithImages
.Select(c => new ValueTuple<string, Image>(c.Name, Image.FromStream(new MemoryStream(c.Image.Image))))
.ToList();
使用记录是另一种选择(需要c# 9+):
List<ImageData> values = CategoriesWithImages
.Select(c => new ImageData(c.Name, Image.FromStream(new MemoryStream(c.Image.Image))))
.ToList();
record struct ImageData(string Name, Image Image);
注意:结构型记录需要c# 10+
现在Context.Categories.Include(c => c.Image)
在内存中加载了整个Categories
和Images
表。这是浪费的
更好的方法是从数据库中只检索必要的字段,并且不使用Image
。与System.Drawing
名称空间中的所有类型一样,这个类仅用于使用GDI+在桌面屏幕上绘图,并且使用有限的操作系统范围资源。这就是为什么没有Image.FromBytes
的原因——映像应该存储在本地磁盘上,或者从应用程序的资源中加载。
从评论来看,似乎有大约20个缩略图,每个15KB,显示在Windows窗体应用程序中。
LINQ查询可以只加载名称和图像作为byte[]
数组,在字典或列表中,这取决于使用:
record MyImage(string Name,byte[] Content);
...
var categoryThumbnails=await Context.Categories
.ToListAsync(new MyImage(c.Name,c.Image.Image));
或
Dictionary<string,byte[]> categoryThumbnails=await Context.Categories
.ToDictionaryAsync(c=>c.Name,c=>c.Image.Image));
EF Core将在Categories和Image表之间生成必要的join,并且只加载Name
和Image
属性。
Bitmap(string)
构造函数从磁盘加载它们。