【问题标题】:C# Automapper IQueryable - LINQ 2 SQLite - Query returns only parent, nested child always nullC# Automapper IQueryable - LINQ 2 SQLite - 查询仅返回父级,嵌套子级始终为空
【发布时间】:2020-07-07 10:45:27
【问题描述】:

互联网的人们,嗨,

我已经在 SO 上搜索了几天,尝试了很多可能的解决方案,但我无法在以下测试项目中解决我的问题。 请原谅我缺乏技能,因为我是一名自学成才的程序员才一年多,这是我关于 SO 的第一个问题。

情况: 我有 2 个实体类 CarWheel 并希望使用 c# 的 linq to sql(ite) 从单个 db 表中存储和查询它们。

    public class Car
    {
        public Int64? Id { get; private set; }
        public string Manufacturer { get; private set; } = "Porsche";
        public double Mileage { get; private set; }
        public Wheel Wheel { get; private set; }

        public Car()
        {
            this.Id = Program.CarCount;
            Mileage = new System.Random(Program.CarCount).Next(0, 500000);

            Program.CarCount++;
        }

        public Car CreateWheels()
        {
           // Adds Wheel 2 Car
        }
    }

    public class Wheel
    {
        public Int64? Id { get; set; }
        public string Manufacturer { get; set; } = "Continental";

        public Wheel() { Id = Program.WheelCount; }
    }

不幸的是,由于它是我正在处理的另一个项目的测试项目,我无法将原始数据拆分为多个 OR 表。

为了使用单个表,我将它们展平为与我的单个 db 表匹配的单个 CarDto 类。 我使用 AutoMap 将这两个类扁平化为 CarDto,以便与 LINQ 2 SQLite 一起使用并分配各个 db 列。

    [Table(Name = "Cars")]
    [AutoMap(typeof(Car), ReverseMap = true)]
    public class CarDto
    {
        public CarDto(){ }

        [Column(IsPrimaryKey = true)]
        public Int64? Id { get; set; }
        [Column]
        public string Manufacturer { get; set; }
        [Column]
        public double Mileage { get; set; }
        [Column]
        public Int64? WheelId { get; set; }
        [Column]
        public string WheelManufacturer { get; set; }
    }

DTO 类和实体类之间的映射是通过一个映射器 CarMapper 使用 AutoMapper v.9x

完成的
    public class CarMapper
    {
        public IMapper Map => Config.CreateMapper();
        IConfigurationProvider Config;

        public CarMapper()
        {
            Config = new MapperConfiguration(cfg =>
            {
                cfg.AddMaps(typeof(CarMapper).Assembly);
            });
            Config.AssertConfigurationIsValid();
        }
    }

与数据库的交互通过包含映射器的存储库类 CarRepo 和 C# Linq2SQL 的 DataContext 类处理

    public class CarContext : DataContext
    {
        public Table<CarDto> CarDtos;
        public CarContext(IDbConnection connection) : base(connection) { }
    }

    public class CarRepo
    {
        private string conn;
        CarMapper mp = new CarMapper();
        CarContext CarContext => new CarContext(new SQLiteConnection(conn));
        public IQueryable<Car> Cars { get => Qry(); }

        public CarRepo(string connectionString) { this.conn = connectionString; }

        private IQueryable<Car> Qry()
        {
            return mp.Map.ProjectTo<Car>(CarContext.CarDtos);
        }

        public List<Car> GetAllCarsFromDb()
        {
            var dtosFromDb = new List<CarDto>();
            using (var db = CarContext)
                return mp.Map.Map<List<CarDto>, List<Car>>(db.CarDtos.ToList());
        }

        public void InsertCars(List<Car> cars)
        {
            using (var db = CarContext)
            {
                db.CarDtos.InsertAllOnSubmit(mp.Map.Map<List<Car>, List<CarDto>>(cars));
                db.SubmitChanges();
            }
        }
    }

问题:

CarDto-table 插入和映射到Car 可以完美运行。运行 repo.Cars.Where(car =&gt; car.Id &lt;= 5).ToList(); 会产生预期结果,但嵌套对象 Wheel 除外,它始终返回为 null。投影汽车查询时存在问题,可能在于查询表达式的映射。查看生成的查询,这似乎很明显。

SELECT[t0].[Id], [t0].[Manufacturer], [t0].[Mileage]
FROM[Cars] AS[t0]
WHERE[t0].[Id] <= @p0

运行以下映射 mp.Map.Map&lt;List&lt;CarDto&gt;, List&lt;Car&gt;&gt;(db.CarDtos.ToList()); 可以工作并交付 Car,包括 Wheel 实例。

我尝试了很多解决方案(自定义映射,...)并浏览了 AutoMapper 文档,但无法解决我的问题。希望可以有人帮帮我。

来自德国的干杯! 亨里克

编辑: 附:我添加了一个要点https://gitlab.com/snippets/1957648 https://gist.github.com/henrikherr/29eb2913d403ab1d6bede52ed011869a

【问题讨论】:

  • 谢谢@LucianBargaoanu。生成的表达式反映了缺少的 Wheel 选择。 expression = {Table(CarDto).Select(dtoCarDto =&gt; new Car() {Id = dtoCarDto.Id, Manufacturer = dtoCarDto.Manufacturer, Mileage = dtoCarDto.Mileage})}
  • 公开设置器。
  • 谢谢@LucianBargaoanu!但遗憾的是,让二传手公开并没有帮助。像mapper.Map&lt;CarDto,Car&gt;(dto) 这样的“标准”映射也可以正常工作,返回包含嵌套Wheel(来自dto-db)的Car,反之亦然。
  • 您在这里隐式依赖ForPath,而这不适用于ProjectTo。但是您的实体/ dto 完全相反。 Car 应该在数据库中,带有Wheel FK 实体。 CarDto 会出现在 UI 中,或者任何使用 DB 的地方。

标签: c# linq linq-to-sql automapper iqueryable


【解决方案1】:

正如@LucianBargaoanu 指出的ProjectTo 不适用于ForPath。他还正确地指出,我的 dto 和实体的逻辑/用法是相反的。

此外,如果我的 db-design 会以更多类/对象相关的方式匹配我的 CarWheel 类,或者如果我的 repo 会公开和处理dto 类。

您在此处隐式依赖 ForPath,这不适用于 ProjectTo。但是您的实体/ dto 完全相反。 Car 应该在 DB 中,带有 Wheel FK 实体。 CarDto 会出现在 UI 中,或者任何使用数据库的地方。 ——卢西安·巴尔高阿努

【讨论】:

    猜你喜欢
    • 2013-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-26
    • 2021-09-05
    • 2016-02-11
    • 2021-07-27
    • 2020-12-08
    相关资源
    最近更新 更多