Динамическое изменение типа параметра в выражении без знания целевого типа во время кода - PullRequest
0 голосов
/ 10 декабря 2018

Допустим, у меня есть класс Animal, у которого есть несколько потомков, которые происходят от него, например Dog Cat и Mouse

public class Animal{}
public class Dog : Animal {}
public class Cat : Animal {}
public class Mouse: Animal {}

Теперь допустим, что объекты этих объектов хранятся вБаза данных SQL и что я использую Entity Framework для связи с этой базой данных.Собаки, кошки и мыши все хранятся в разных таблицах, но в коде у них один и тот же родительский элемент, от которого они происходят.

Если я хочу получить всех животных, которые соответствуют одному и тому же выражению, я бы запросил каждый DbSetотдельно и дать ему то же выражение, но с другим типом параметра, поэтому кошка получает тип параметра кошка, а собака получает параметр собаки, подобный этому

var cats = context.Cats.Where(p=>some expression);
var dogs= context.Dogs.Where(p=>some expression);
var mice= context.Mice.Where(p=>some expression);
var animals = new List<Animal>();
animals.AddRange(cats);
animals.AddRange(dogs);
animals.AddRange(mice);

Но это создает для меня проблему, потому чтоесли бы я захотел добавить другой тип животных, например Bird, мне пришлось бы добавить еще одну строку кода, которая получает данные из базы данных и добавляет их в коллекцию результатов.Это поведение плохо управляемо, и я бы хотел, чтобы оно циклически проходило типы, производные от Animal, и программно создавало выражение для правильного типа на основе предоставленного исходного выражения, которое передается в качестве параметра методу как выражение типа Animal.Примерно так:

public List<Animal> GetAnimals(Expression<Func<Animal, bool>> expression)
{
    var animalTypes = GetTypesDerivingFrom(typeof(Animal));
    List<Animal> animals = new List<Animal>();
    foreach(var animalType in animalTypes)
    { 
        var typeTranslatedExpression = GetTypeTranslatedExpression(expression); //i dont know how to do this part
        var portionOfAnimals = context.Set(animalType).Where(typeTranslatedExpression).ToList();
        animals.AddRange(portionOfAnimals);
    }
    return animals;
}

Есть ли способ сделать это?Я думал об изменении типа параметра выражения, но я не могу понять это, не зная правильный тип параметра во время кода.

Ответы [ 3 ]

0 голосов
/ 10 декабря 2018

А может предложить вам более простое решение.Поскольку в коде у вас есть Animal в качестве родителя, вы можете сделать то же самое для базы данных.

Точнее, вместо того, чтобы иметь разные таблицы для Cats, Dogs и т. Д., Есть одна таблица Animal (поскольку свойствадолжно быть таким же), со свойством что-то вроде «AnimalType», перечислением.

И отсюда запросы будут очень простыми.

Это не лучшее решение, но оно жизнеспособное.

0 голосов
/ 10 декабря 2018

Мне нравится использовать возможности приложения базы данных, а не предполагать, что код C # (для извлечения данных) более эффективен.Я также вижу это как разделение проблем.Это тот случай, когда требуется определенный навык в настройке таблиц базы данных (ключ, другие индексы и т. Д.), А также представлений, хранимых процедур и т. Д.

Наследование объектов в базе данных не является необычным сценарием,Вы можете пойти несколькими путями по этому поводу.Что лучше, зависит не в последнюю очередь от того, сколько строк и столбцов задействовано и что вы хотите сделать с данными.В качестве примера приведем иерархию животных: - В наследовании принято продвигать обобщение вверх и специализацию вниз, поэтому мы начнем с создания таблицы «Животные».Это имеет целочисленное поле «Id», которое является ключом.У нас также есть поле «Имя животного».

Теперь давайте создадим таблицу «Кошка».И поле «Id» используется, но у нас есть внешний ключ «AnimalId», который ссылается на таблицу животных «Id».Мы добавляем другие поля, общие для кошек.Мы делаем то же самое для мышей и других животных, почти так же, как вы начали.

Еще один способ достичь вышесказанного - использовать одну таблицу для всех животных.Теперь вам нужно больше столбцов для большего количества типов животных.Это более высокий подход к обслуживанию, при котором изменения могут происходить часто, но он хорошо работает, когда используются меньшие фиксированные диапазоны объектов.Простой способ получить некоторые общие данные независимо от типа - использовать вычисляемый столбец, который выводит varchar из соответствующих полей для каждого типа объекта.

Еще один способ - создать одну таблицу животных со всемиобщие свойства.Во второй таблице хранятся пары «Имя свойства / Значение».Каждое животное теперь может иметь любое количество различных свойств, и его легко поддерживать из кода переднего плана.Эта структура данных имеет простой фиксированный дизайн, но все же поддерживает все, что у вас есть до сих пор.Однако насколько полезен этот дизайн для вас, зависит от того, насколько требуется анализ данных.В базе данных вам придется сгладить эти данные на основе строк в столбцы для некоторой обработки анализа.

0 голосов
/ 10 декабря 2018

Я думаю, вам стоит снова взглянуть на свой дизайн данных.Именно здесь вы можете решить множество своих проблем.

Вы можете использовать SQL SERVER VIEW, чтобы вернуть животных из разных таблиц, используя UNION из соответствующих таблиц.Добавление новой таблицы животных требует нового UNION в представлении.

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

Вы можете хранить всех животных в одной таблице и иметь поле AnimalType, которое ссылается на другую простую таблицу с идентификатором иAnimalTypeName.Добавление новых животных тогда просто.

Существует также наследование Entity Framework с таблицами для рассмотрения https://weblogs.asp.net/manavi/inheritance-mapping-strategies-with-entity-framework-code-first-ctp5-part-2-table-per-type-tpt

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...