Страницы

Поиск по вопросам

четверг, 23 января 2020 г.

Работа с БД через Sqlite-Net

#c_sharp #sql #aspnet #aspnet_mvc #sqlite


У меня в проекте есть два класса для работы с пользователями, и библиотека https://github.com/praeclarum/sqlite-net/

Первый класс:

public class User
{
    [PrimaryKey, AutoIncrement]
    public int Id { get; set; }

    public string UserName { get; set; }

    public string Password { get; set; }

    public string IP { get; set; }

    public Profile userProfile { get; set; }

    public UserGroup Role { get; set; } // enum
}


Второй класс:

public class Profile
{
    public string PhotoUrl { get; set; }

    public int Rating { get; set; }

    public string DisplayName { get; set; }

    public string FirstName { get; set; }

    public string LastName { get; set; }

    public string Age { get; set; }

    public DateTime RegistrationDate { get; set; }
}


Но вот тут в чем дело, Sqlite-net не поддерживает использование класса в роли переменной,
соответственно вставить данные в таблицу нельзя и в итоге он давится на строке:

    public Profile userProfile { get; set; }


В качестве quick fix'а пришлось скопипастить все поля класса Profile в класс User,
но вот тут другая проблема: предполагается что другие могут просмотреть профиль пользователя,
но вот доставать из БД данные с паролем и передавать в представление класс как-то не
охото, что мне делать? Хранить все в разных таблицах?

До этого использовал Mono SQLite и делал все запросы вручную, но получалось очень
много кода. Profile и User хранились в одной таблице, просто для Profile выбирались
не все столбцы,а только определенные.
    


Ответы

Ответ 1



Про профиль вам Andrew Prigorshnev уже ответил, перейдем к паролям. Для чего вы вообще храните пароль пользователя в БД открытым текстом? Если стоит задача проверять пароль, введенный пользователем - надо использовать криптостойкие хеши. Хорошей практикой является хранение в БД следующих вещей вместо пароля: кода используемого криптоалгоритма - со временем могут появляться новые алгоритмы, на которые надо переходить - но пароль пользователя надо проверять тем алгоритмом, которым он хешировался, так называемой соли - случайной строки из эдак восьми символов, дописываемой к паролю пользователя перед хешированием (соль нужна для защиты от атаки методом радужных таблиц), хеша пароля (это массив байт). Иногда вместо трех отдельных полей в БД хранят строку в следующем формате: $код алгоритма$соль$хеш-в-base64 Как происходит установка такого пароля? Сначала генерируется соль. Потом берется текущий алгоритм вычисления криптостойкого хеша - и вычисляется хеш-функция от пароля и соли. Далее код алгоритма, соль и хеш-код пароля записываются в БД. Как проверить такой пароль? Из базы достаются код алгоритма, соль и хеш-код. Соль складывается с паролем, который ввел пользователь - и от них вычисляется хеш-функция в соответствии с кодом алгоритма, полученным из базы. Полученный хеш-код сравнивается с кодом, полученным из базы. Если они совпадают - то пароль правильный. Далее сравниваются код текущего используемого алгоритма и код алгоритма, хранящийся в базе. Если они различаются, а пароль пользователь ввел правильный - то пароль в БД обновляется в соответствии с прошлым пунктом (это нужно для постепенного перехода с устаревших алгоритмов на новые). Что еще надо знать про пароли? Профиль пользователя и данные для входа должны лежать в разных таблицах. Причем "основной" записью, на которую ссылаются другие, должен быть именно профиль, а не учетные данные. Это позволит загружать профиль пользователя не загружая пароль лишний раз. Кроме того, это же позволит в дальнейшем реализовать и несколько учетных данных для одного пользователя, профили пользователей без учетных данных (заблокированные, к примеру), профили пользователей, привязанные к социальным сетям и т. д.

Ответ 2



Насколько я вижу из вопроса - суть вашей проблемы в том, что вы пытаетесь сократить объем ручной работы по написанию sql-запросов, сократить объем кода и повысить его надежность. Традиционно эта задача решается с помощью ORM - фреймворков. И библиотека sqlite-net, которую вы используете, очевидно представляет собой одно из таких решений. Ваша библиотека написана специально для sqlite, и в целом решает ваши задачи, но она не умеет отображать реляционные связи на ссылочные свойства в классах. Решить вашу проблему можно следующим образом. Вместо поиска библиотеки предназначенной специально для sqlite, посмотрите в сторону универсальных ORM-фреймворков, прежде всего: NHibernate - опенсорсный, активно-развивающийся и имеющий долгую историю, уходящую корнями в Java (NHibernate это портрированный с Java ORM-фреймворк Hibernate) Entity Framework - полнофункциональное решение от Майкрософт, тоже с открытым исходным кодом Оба фреймворка работают с различными базами данных, в том числе с Sqlite. Оба фреймворка умеют делать то что вы хотите - отображать реляционные связи на ссылочные свойства в классах. Кроме того оба фреймворка умеют делать гораздо больше чем то, что вам потребовалось на текущем этапе, например умеют самостоятельно кэшировать результаты запросов к базе данных. Только имейте в виду, что эти фреймворки в силу своей развитости довольно сложны, и для полноценной работы с ними вам придется потратить некоторое время на их изучение.

Ответ 3



Модели, передаваемые в представление, должны отражать структуру представления. Класы, описывающие сущности, должны отражать структуру предметной области. Просто заведите отдельный набор классов для передачи из сервисов (BL) на уровень представления (PL) - DTO - и оставьте в них только те поля, которые стоит возвращать для конкретной операции. Для маппинга одних классов на другие можно взять Automapper - он просто перебросит данные из полей, совпадающих по названию. Или просто написать маппинг вручную (если полей мало).

Комментариев нет:

Отправить комментарий