Я хотел бы поделиться своим решением этой проблемы и посмотреть, есть ли у кого-нибудь конструктивные отзывы о подходе, который я использовал?
У меня есть несколько требований в проекте, над которым я работаю, и мне нужно сначала объяснить:
- Я должен держать свои POCO как можно более чистыми, так как эти классы будут публично предоставлены в обертке API.
- Мои POCO находятся в отдельной библиотеке классов из-за вышеуказанного требования
- Будет несколько уровней иерархии объектов, которые будут варьироваться в зависимости от данных (поэтому я не могу использовать средство отображения универсального типа, или мне придется написать тонны из них, чтобы удовлетворить все возможные случаи)
Итак, я сделал так, чтобы SQL обрабатывал иерархию 2-го уровня, возвращая одну строку JSON в виде столбца в исходной строке следующим образом ( удалил другие столбцы / свойства и т. Д., Чтобы проиллюстрировать это ):
Id AttributeJson
4 [{Id:1,Name:"ATT-NAME",Value:"ATT-VALUE-1"}]
Затем мои POCO создаются следующим образом:
public abstract class BaseEntity
{
[KeyAttribute]
public int Id { get; set; }
}
public class Client : BaseEntity
{
public List<ClientAttribute> Attributes{ get; set; }
}
public class ClientAttribute : BaseEntity
{
public string Name { get; set; }
public string Value { get; set; }
}
Где POCO наследуется от BaseEntity. (Для иллюстрации я выбрал довольно простую одноуровневую иерархию, как показано свойством «Атрибуты» клиентского объекта.)
У меня на уровне данных есть следующий «класс данных», который наследуется от POCO Client
.
internal class dataClient : Client
{
public string AttributeJson
{
set
{
Attributes = value.FromJson<List<ClientAttribute>>();
}
}
}
Как вы можете видеть выше, происходит то, что SQL возвращает столбец с именем "AttributeJson", который сопоставляется со свойством AttributeJson
в классе dataClient. У него есть только установщик, который десериализует JSON в свойство Attributes
унаследованного класса Client
. Класс dataClient для уровня доступа к данным равен internal
, а ClientProvider
(моя фабрика данных) возвращает исходный клиентский POCO вызывающему приложению / библиотеке следующим образом:
var clients = _conn.Get<dataClient>();
return clients.OfType<Client>().ToList();
Обратите внимание, что я использую Dapper.Contrib и добавил новый Get<T>
метод, который возвращает IEnumerable<T>
В этом решении есть пара моментов, на которые следует обратить внимание:
Есть очевидный компромисс производительности с сериализацией JSON - я сравнил это с 1050 строками с 2 вложенными List<T>
свойствами, у каждого из которых есть 2 объекта в списке, и он работает с 279 мс - что является приемлемым для нужд моего проекта - это также с ZERO-оптимизацией на стороне SQL, поэтому я смогу побриться там на несколько мс.
Это означает, что для создания JSON для каждого требуемого свойства List<T>
требуются дополнительные запросы SQL, но, опять же, мне это подходит, поскольку я довольно хорошо знаю SQL и не очень хорошо разбираюсь в динамике / отражении и т. Д. таким образом, я чувствую, что у меня больше контроля над вещами, поскольку я действительно понимаю, что происходит под капотом: -)
Возможно, найдется лучшее решение, чем это, и если оно будет, я был бы очень признателен, если бы вы услышали ваши мысли - это только то решение, которое я придумал, которое до сих пор соответствует моим потребностям в этом проекте (хотя это экспериментально на этап размещения).