Похоже, что здесь есть три взаимосвязанные вещи, хотя вопрос вращается вокруг одной:
- Как данные хранятся в базе данных?
- КакВы гарантируете, что каждый пользователь имеет доступ только к тем экземплярам, на которые у него есть права?
- Как сопоставить данные с объектами для использования в коде?
Возможно, есть несколько способовчтобы решить каждый из них, но вот что я буду делать:
Как данные хранятся в базе данных?
Поскольку у вас есть одна база данных на экземпляр клиентаприложения (каждая «среда» - производство, тестирование и т. д. будет экземпляром арендатора), и у вас есть данные, относящиеся ко всем из них, я бы также сохранил «общие» данные в отдельной базе данных.
Давайте назовем эту базу данных базой данных SystemConfiguration.При этом у вас будет:
- Список всех клиентов в системе.
- Список глобальных параметров конфигурации каждого экземпляра (например, имя базы данных, конечные точки службы и т. Д.).), каждый экземпляр сопоставлен с арендатором.
- Список всех пользователей в системе, каждый из которых сопоставлен с арендатором (при условии, что один пользователь не может пересекать арендаторов ... что может быть сложным, ноне невозможно).
- Отображение пользователей на идентификаторы каждого экземпляра, к которому имеет доступ каждый пользователь.
Отключение этой базы данных SystemConfiguration как ее собственной вещи означает, что у вас нетпытаться синхронизировать общую информацию о пользователях в любом месте.Если для каждого экземпляра есть пользовательская информация (например, пользовательские настройки или что-то еще), она будет помещена в базу данных экземпляра, но имя, хэш пароля и т. Д. Все будет в этой центральной базе данных.
Технически вы могли быразделите это другими способами, например, имея отдельную пользовательскую базу данных и сохраняя только конфигурацию клиента / системы в базе данных SystemConfiguration, но это, по крайней мере, дает вам представление.
Если арендатор решает покинуть его, онбыло бы довольно просто запросить любую информацию, относящуюся к конкретному арендатору, и экспортировать ее из базы данных SystemConfiguration.Не должно быть много по сравнению с количеством специфичных для арендатора данных в базах данных экземпляров.
Как вы гарантируете, что каждый пользователь имеет доступ только к тем экземплярам, на которые у него есть права?
Я думаю, что аутентификация / авторизация на основе утверждений значительно упростила бы эту проблему.Если вы не знакомы с утверждениями, идея заключается в том, что вместо статического списка «ролей», в которых находится пользователь, у вас есть словарь пар имя / значение, связанных с каждым пользователем.Словарь является «набором требований» пользователя, а каждая пара «имя / значение» является «утверждением».Преимущество перед ролями заключается в том, что значение может быть любым, включая список.
Пользователям после проверки подлинности будет выдан набор утверждений, включая их имя пользователя, их имена / фамилии и список экземпляров, которые онииметь доступ к.
После этого нужно просто проверить утверждения пользователя по идентификатору текущего экземпляра.Если аутентифицированный пользователь не имеет доступа к этому экземпляру, заблокируйте его.
Возвращение его в хранилище данных - генерация набора заявок из этой базы данных SystemConfiguration будет тривиальным запросом.
Подробнее об идентификации на основе утверждений и о том, как использовать Windows Identity Foundation для работы в вашем приложении, см. Программирование Windows Identity Foundation , автор Vittorio Bertocci .Это хорошая книга ... и почти единственная книга по WIF.
Как вы сопоставляете данные с объектами для использования в коде?
На этомДело в том, что речь идет скорее о представлении данных из вашего кода, чем о структуре хранилища данных.Если вы хотите, чтобы объект Арендатора имел IEnumerable в нем, это все просто возражает с ORM по вашему выбору.
Я мог бы предложить обернуть операции, по крайней мере, вокруг базы данных SystemConfiguration, с контрактом на обслуживание, поэтому, если вы измените данные под ним, вы можете настроить ORM на уровне обслуживания, а не на потребляющем коде. Интерфейсы!
В любом случае, суть в том, что я не буду пытаться основывать хранилище данных на том, как вы потребляете данные.
Наконец, если вам понадобится информация о пользователях или арендаторах в ваших экземплярах, в конечном итоге некоторые запросы будут обращаться к базе данных SystemConfiguration, а другие - к базе данных экземпляра арендатора. Это нормально. Пока вы используете глобально уникальный идентификатор для всего, вы можете привязать пользователя из одной базы данных к некоторому параметру или значению в другой, просто по идентификатору. Поддерживать ссылочную целостность немного сложнее, но проще, чем поддерживать синхронизацию данных в нескольких базах данных экземпляров.
Это может быть еще одна причина, чтобы обернуть вещи в услуги. Например, если у вас есть служба «UserSettings», ваш контракт может запрашивать идентификатор экземпляра клиента и идентификатор пользователя и возвращать список настроек. За кулисами служба может запрашивать данные из SystemConfiguration, сопоставлять их с соответствующей базой данных экземпляра и возвращать объединенный набор данных - все прозрачно для вызывающего кода. С другой стороны, вы не получаете того приятного метода «Update ()», который дают вам некоторые ORM, когда вы просто изменяете значения в объектах и хотите зафиксировать изменения. Это компромисс между тем, хотите ли вы привести ORM в соответствие, чтобы это произошло.