C# Automapper IQueryable - LINQ 2 SQLite - Запрос возвращает только родительский, вложенный дочерний всегда нулевой - PullRequest
2 голосов
/ 26 марта 2020

Привет, люди из всего мира rnet,

Я искал в SO уже несколько дней, пробовал множество возможных решений, но я не могу решить свою проблему в следующем тест-проект. Прошу извинить меня за недостаток навыков, так как я программист-самоучка уже чуть больше года, и я это мой первый вопрос по SO.

Ситуация : У меня есть 2 класса сущностей Car и Wheel, и я хочу сохранить их и запросить их из одной таблицы БД, используя c# linq to sql (ite).

    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.

Чтобы работать с одной таблицей, вместо этого я объединяю их в один класс CarDto, который соответствует моей единой таблице БД. Я сглаживаю оба класса в CarDto для использования с LINQ 2 SQLite, используя AutoMap и назначая отдельные столбцы БД.

    [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, содержащий маппер и класс DataContext C# Linq2 SQL

    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 в Car работает безупречно. Запуск repo.Cars.Where(car => car.Id <= 5).ToList(); приводит к ожидаемым результатам, за исключением вложенного объекта Wheel, который всегда возвращается как ноль. Проблема существует при проецировании автомобильного запроса и, вероятно, заключается в отображении выражения запроса. Глядя на полученный запрос, это кажется очевидным.

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

Запуск следующего сопоставления mp.Map.Map<List<CarDto>, List<Car>>(db.CarDtos.ToList()); работает и доставляет Car, включая Wheel экземпляров.

Я перепробовал множество решений (пользовательских сопоставлений, ...) и прошел через документация AutoMapper, но не смогла решить мою проблему. Надеюсь, кто-нибудь может мне помочь.

Приветствия из Германии! Хенрик

РЕДАКТИРОВАТЬ: Ps я добавил гист https://gitlab.com/snippets/1957648 https://gist.github.com/henrikherr/29eb2913d403ab1d6bede52ed011869a

1 Ответ

1 голос
/ 27 марта 2020

Как отметил @LucianBargaoanu, ProjectTo не работает с ForPath. Он также правильно указал, что логика / использование моего dto и сущностей полностью изменено.

Кроме того, мне не нужно было бы делать отображение iqueryable, если бы мой db-дизайн соответствовал моим Car и Wheel классам в большей степени, относящимся к классам / объектам, или если бы мой репо представлял и обработайте класс dto.

Вы неявно полагаетесь на ForPath, а это не работает с ProjectTo. Но вы, сущности / dtos, полностью изменились Автомобиль должен быть в БД, с колесом ФК. И CarDto будет отображаться в пользовательском интерфейсе или в любом другом месте, где используется БД. - Люсьен Баргаоану

...