根据外键 ID 将列值传递给来自不同 table 的模型

Pass a column value to model from a different table based on foreign key id

我有一个 products table,它有一个 CategoryId,代表 Categories table.

中的相应主键

ProductViewModel

public ProductVM(ProductDTO productDTO)
{
    Id = productDTO.Id;
    Name = productDTO.Name;
    Description = productDTO.Description;
    Price = productDTO.Price;
    CategoryId = productDTO.CategoryId;
    ImageName = productDTO.ImageName;
}

public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Description { get; set; }
[Required]
public decimal Price { get; set; }

public int? CategoryId { get; set; }
public IEnumerable<SelectListItem> Categories { get; set; }
public string ImageName { get; set; }
public IEnumerable<string> GalleryImages { get; set; }

产品 DTO

public class ProductDTO
{
    [Key]
    public int Id { get; set; }
    public string Name { get; set; }
    public string Slug { get; set; }
    public string Description { get; set; }
    public decimal Price { get; set; }
    public int CategoryId { get; set; }
    public string ImageName { get; set; }

    [ForeignKey("CategoryId")]
    public virtual CategoryDTO Category { get; set; }
}

这是我获得产品列表的方式:

List<ProductVM> productVM;
using (Db db = new Db())
{
    productVM = db.Products
        .ToArray()
        .Select(x => new ProductVM(x))
        .ToList();
}

如您所见,我正在传递 CategoryId,我可以使用 ProductVM ViewModel 在我的视图中显示它,但我也想获得 Name类别也在那里。

我能想到一些技巧,例如基于 CategoryIdViewModel 中的构造函数访问 DB 并以这种方式分配它,但我想看看是否有更优雅的解决方案?

底线 - 我的 Categories table 中有一个 Name 列,我想以最有效的方式将该名称传递给 ProductVM

为类别名称添加一个 属性 模型,比如

public string CategoryName { get; set; }

并修改构造函数来填充它

public ProductVM(ProductDTO productDTO)
{
    CategoryName  = productDTO.Category.Name;
    ....

并将查询修改为

List<ProductVM> productVM = db.Products.AsEnumerable().Include(x => x.Category)
    .Select(x => new ProductVM(x)).ToList();

请注意,如果您使用它进行编辑,您的视图模型还需要一个无参数构造函数,否则将在 POST 方法中抛出异常。

另请注意,您不需要 using (Db db = new Db())

最佳解决方案如下(我删除了所有其他答案)

namespace Test
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;
    using System.Data.Entity;
    using System.Linq;

    internal class Program
    {
        private static void Main(string[] args)
        {
            List<ProductVM> productVM;
            //It doesn't matter if you use a using block or not
            using (Db db = new Db())
            {
                db.Database.Log = Console.WriteLine;//To see the generated SQL

                productVM = db.Products
                              .Include(p => p.Category)
                              .Select(p => new ProductVM
                              {
                                  Id = p.Id,
                                  Name = p.Name,
                                  Description = p.Description,
                                  Price = p.Price,
                                  CategoryId = p.CategoryId,
                                  CategoryName = p.Category.Name,
                                  ImageName = p.ImageName,
                              }).ToList();



            }

            Console.ReadKey();
        }
    }

    public class Db : DbContext
    {
        public DbSet<ProductDTO> Products { get; set; }
        public DbSet<CategoryDTO> Categories { get; set; }
    }

    public class ProductDTO
    {
        [Key]
        public int Id { get; set; }

        public string Name { get; set; }
        public string Slug { get; set; }
        public string Description { get; set; }
        public decimal Price { get; set; }
        public int CategoryId { get; set; }
        public string ImageName { get; set; }

        [ForeignKey("CategoryId")]
        public virtual CategoryDTO Category { get; set; }
    }

    public class CategoryDTO
    {
        [Key]
        public int Id { get; set; }

        public string Name { get; set; }
    }

    public class ProductVM
    {
        public int Id { get; set; }

        [Required]
        public string Name { get; set; }

        [Required]
        public string Description { get; set; }

        [Required]
        public decimal Price { get; set; }

        public int? CategoryId { get; set; }
        public string CategoryName { get; set; }
        public string ImageName { get; set; }
    }
}