【问题标题】:Is there a way to get to list a query of an object under a primary key id? the object itself has foreignkey referenced on the main table in aspnetcore有没有办法在主键 ID 下列出对象的查询?对象本身在 aspnetcore 的主表上引用了外键
【发布时间】:2021-09-23 13:17:20
【问题描述】:

我有两个“卖家和车辆表”两个表,我想获取卖家创建的车辆列表。卖家表有主键Id和车辆'VehicleId'的外键引用,卖家通过sellerid应该可以得到自己创建的车辆列表。 我的意思是,sellerid 应该得到他/她创建的车辆列表。

请检查我在 SellerRepository 中尝试过的代码

这是卖家表

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Models
{
    public class Seller
    {
        public int Id { get; set; }
        [Required]
        public int VehicleId { get; set; }
        [ForeignKey("VehicleId")]
        public Vehicle Vehicle { get; set; }
        public string Name { get; set; }
        public string Title { get; set; }
        [EmailAddress(ErrorMessage = "Invalid Email ID")]
        [StringLength(50)]
        public string SellerEmail { get; set; }
        public int Age { get; set; }
        public string Sex { get; set; }
        public string Company { get; set; }
        public string Address { get; set; }
        public int SellerPhone { get; set; }
        public string City { get; set; }
        public string Country { get; set; }
        public int PhoneNo2 { get; set; }
        public string PostalCode { get; set; }
        [Display(Name = "Profile Image")]
        [StringLength(100)]
        public string ProfileImagePath { get; set; }

    }
}

这是车辆表

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
using Utility.Extensions;

namespace Models
{
    public class Vehicle
    {
        
        public int Id { get; set; }
        public Make Make { get; set; }
        [RegularExpression("^[1-9]*$", ErrorMessage = "Select Make")]
        public int MakeID { get; set; }
        public Model Model { get; set; }
        [RegularExpression("^[1-9]*$", ErrorMessage = "Select Model")]
        public int ModelID { get; set; }
        [Required(ErrorMessage = "Provide Year")]        
        [YearRangeTillDate(2000,ErrorMessage = "Not with in the valid Year range")]
        public int Year { get; set; }

        [Required(ErrorMessage = "Enter Mileage")]
        [Range(1,int.MaxValue,ErrorMessage ="Not with in the valid mileage range")]
        public int Mileage { get; set; }

        
        public string Features { get; set; }

        [Required(ErrorMessage ="Provide Seller Name")]
        [StringLength(50)]
        public string SellerName { get; set; }

        [EmailAddress(ErrorMessage ="Invalid Email ID")]
        [StringLength(50)]
        public Seller SellerEmail { get; set; }

        [Required(ErrorMessage = "Provide Phone No.")]
        [Phone]
        [StringLength(15)]
        public Seller SellerPhone { get; set; }
        [Required(ErrorMessage = "Provide Price")]
         [Range(1, 999999999, ErrorMessage = "Not with in the valid price range")]
        public int Price { get; set; }
        [Required]
        [StringLength(10)]
        [RegularExpression("^[a-zA-Z]*$", ErrorMessage ="Select Currency")]       
        public string Currency { get; set; }

        [Display(Name ="Image File")]
        [StringLength(100)]
        public string ImagePath { get; set; }

    }
}

ISellerRepository。

using Microsoft.AspNetCore.Mvc.Rendering;
using Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Persistence.Repository.IRepository
{
    public interface ISellerRepository : IRepository<Seller>
    {
        IEnumerable<SelectListItem> GetModelListForDropDown();
       // void Update(Seller model);
        Task<bool> SellerOwnsVehicleAsync(int sellerId, int vehicleId);

    }
}

SellerRepository 获取卖家创建的车辆列表

using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using Models;
using Persistence.Repository.IRepository;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Persistence.Repository
{
    public class SellerRepository : Repository<Seller>, ISellerRepository
    {
        private readonly AutoServDbContext _db;
        public SellerRepository(AutoServDbContext db) : base (db)
        {
            _db = db;
        }
        public IEnumerable<SelectListItem> GetModelListForDropDown()
        {
            return _db.Sellers.Select(i => new SelectListItem()
            {
                Text = i.Name,
                Value = i.Id.ToString()
            });
        }

        public async Task<bool> SellerOwnsVehicleAsync(int sellerId, int vehicleId)
        {
            var seller = await _db.Sellers.AsNoTracking().SingleOrDefaultAsync(x => x.Id ==     sellerId);

            if (seller == null)
            {
                return false;
            }

            if (seller.VehicleId != vehicleId)
            {
                return false;
            }

            return true;
        }
    }
}

【问题讨论】:

  • Vehicle.SellerEmailVehicle.SellerPhone 在此模型中都返回 Seller 的实例。 VehicleSeller 之间的关系看起来没有正确定义。这可能是您问题的根源。您的请求听起来像您期望 Seller 有多个 Vehicle... 可能在一个名为 Vehicles 的属性中,但您没有在模型中提供。
  • 我也这么认为。您提到了多个车辆,但您在卖方模型中只定义了一个车辆而不是列表:[ForeignKey("VehicleId")] public Vehicle Vehicle { get;放; }

标签: c# asp.net .net linq repository


【解决方案1】:

查看您的模型,Seller 有一个 Vehicle 导航属性,但 Vehicle 有两个导航属性链接回可能不同 Seller 记录:SellerEmailSellerPhone.

卖家通过sellerid应该可以得到自己创建的车辆列表

您的请求指出给定的 Seller 可以有多个 Vehicle 记录,但您的模型不允许这样做。

Vehicle 的当前模型类似于车辆创建或摘要 DTO,但不一定是数据实际存储在数据库或存储库中的方式。结构本身不是无效的,但并不代表数据存储的范式

第一步,更改模型中的关系,从Seller 中取出VehicleIdVehicle,将其替换为集合属性:
注意: 可以保持不变的属性我省略了

public class Seller
{
    public int Id { get; set; }
    //[Required]
    //public int VehicleId { get; set; }
    //[ForeignKey("VehicleId")]
    //public Vehicle Vehicle { get; set; }

    public ICollection<Vehicle> Vehicles { get; set; } = new HashSet<Vehicle>();
    
    ...
}

然后在Vehicle 中进行反向更改,提供返回Seller 的链接。在这个修改后的模型中,每个Vehicle 可以有一个Seller

public class Vehicle
{
    public int Id { get; set; }
    public Make Make { get; set; }
    [RegularExpression("^[1-9]*$", ErrorMessage = "Select Make")]
    public int MakeID { get; set; }
    public Model Model { get; set; }
    [RegularExpression("^[1-9]*$", ErrorMessage = "Select Model")]
    public int ModelID { get; set; }
    [Required(ErrorMessage = "Provide Year")]        
    [YearRangeTillDate(2000,ErrorMessage = "Not with in the valid Year range")]
    public int Year { get; set; }

    [Required(ErrorMessage = "Enter Mileage")]
    [Range(1,int.MaxValue,ErrorMessage ="Not with in the valid mileage range")]
    public int Mileage { get; set; }

    
    public string Features { get; set; }

    // Question: is this necessary, now that we have a Seller
    //[Required(ErrorMessage ="Provide Seller Name")]
    //[StringLength(50)]
    //public string SellerName { get; set; }

    // Removing, no longer relevant
    //[EmailAddress(ErrorMessage ="Invalid Email ID")]
    //[StringLength(50)]
    //public Seller SellerEmail { get; set; }

    // Removing, no longer relevant
    //[Required(ErrorMessage = "Provide Phone No.")]
    //[Phone]
    //[StringLength(15)]
    //public Seller SellerPhone { get; set; }

    public Seller Seller { get; set}
    [Required(ErrorMessage = "Provide Seller")]
    public int SellerID { get; set}

    [Required(ErrorMessage = "Provide Price")]
     [Range(1, 999999999, ErrorMessage = "Not with in the valid price range")]
    public int Price { get; set; }
    [Required]
    [StringLength(10)]
    [RegularExpression("^[a-zA-Z]*$", ErrorMessage ="Select Currency")]       
    public string Currency { get; set; }

    [Display(Name ="Image File")]
    [StringLength(100)]
    public string ImagePath { get; set; }

}

然后我们可以将车辆作为它们自己的端点从SellerRepository 公开:

public IQueryable<Vehicle> VehiclesAsync(int sellerId)
{
    var vehicles = _db.Vehicles.AsNoTracking().Where(x => x.SellerId == sellerId);

    return vehicles;
} 

或者您可以向VehicleRespository 添加一个类似的端点:

public async IQueryable<Vehicle> BySellerAsync(int sellerId)
{
    var vehicles = _db.Vehicles.AsNoTracking().Where(x => x.SellerId == sellerId);

    return vehicles;
} 

使用这种新结构,来自_db.Sellers DbSet 的反向过滤器也可以工作:

_db.Sellers.Where(s => s.Id == sellerId).SelectMany(s => s.Vehicles);

如果您想支持SellerVehicle 之间存在M:N 关系的模型,那么这也可以实现,这将允许Vehicle 拥有多个所有者,有人可能会建议使用为每个所有者记录定义的时间段,但这将涉及一个额外的表来管理关系。

【讨论】:

  • 谢谢克里斯,我之前曾想过在我的卖家模型上使用 ICollection of Vehicle,只是不确定它是否会起作用。而关于 SellerEmail 和 SellerPhone,它与卖方表没有关系,我不应该将卖方作为前缀添加到属性名称。谢谢
  • 它是属性的数据类型,而不是让我担心的它们的名称。您有两个属性都返回Seller 引用,这是多余的,但也令人困惑,这些类实际上允许您将两个不同的Seller 记录链接到相同的Vehicle,我怀疑这是您的意图。拥有Vehicle 的集合对我来说似乎是合乎逻辑的,这些模型和存储库公开指向导航记录和集合的链接是很常见的。 IDK,但由于某种原因,Repository“如何”文档使得这种连接更难建立。
猜你喜欢
  • 1970-01-01
  • 2012-06-13
  • 1970-01-01
  • 2022-10-07
  • 2017-02-03
  • 2011-01-29
  • 1970-01-01
  • 2014-09-05
  • 2021-09-24
相关资源
最近更新 更多