Возможно, одна из проблем заключается в том, что вы сразу начинаете думать о таблицах и идентификаторах и внешних ключах и т. Д. Обычно гораздо проще, если вы думаете об объектах и их отношении друг к другу.
Немного сложно прочитать вашу фотографию. Из текста, который я собираю, у вас есть понятие учетной записи, и, судя по всему, существует три типа счетов: обычные, тренеры и владельцы спортзалов. Есть ли разница между этими счетами? У владельцев спортзалов есть свойства, которых нет у обычных пользователей? или это просто какая-то идентификация.
С вашего рисунка кажется, что у обычного пользователя есть имя пользователя, пароль и уровень доступа. У тренеров также есть эти свойства?
Если это так, то в нормальном объектно-ориентированном дизайне вы бы сказали, что это агрегация: тренеры, обычные люди и владельцы спортзалов все имеют имя пользователя, пароль и уровень доступа. агрегация также довольно часто называется композицией. Существует небольшая разница, но для этого обсуждения это не важно.
Вместо агрегации/составления (объект, который имеет учетную запись) вы также можете думать о наследовании: объект - это учетная запись: учетные записи тренеров, учетные записи владельца тренажерного зала и обычные учетные записи - это объекты, которые являются разными видами учетных записей, с имя пользователя, пароль и уровень доступа.
В этом примере нет большой разницы между агрегацией (у тренера есть учетная запись) или наследованием (учетная запись тренера - это учетная запись). Обычно совет должен поддерживать агрегацию над наследованием enter link description here
Помните: если единственная разница между тремя учетными записями - это значение свойства, а затем подумайте о том, чтобы сделать их одинаковыми, со свойством AccountType, который дает вам информацию о будь то обычная учетная запись, учетная запись владельца тренажерного зала или счет тренера.
Если разница между этими тремя является уровнем доступа, то не создавайте тип учетной записи. Уровень доступа будет служить типом учетной записи.
До сих пор я говорю только о объектно-ориентированном дизайне. Как только вы разработали свои объекты, вы можете подумать о том, чтобы поместить их в базу данных.
Предположим, что тренер, владелец тренажерного зала и нормальные люди действительно разные вещи, с разными свойствами. Ваш класс будет выглядеть так:
public enum AccessLevel
{
None,
...,
FullAccess,
}
public class Account
{
public string UserName {get; set;}
public string Password {get; set;}
public AccessLevel AccessLevel {get; set;}
}
public class Trainer
{
public .. some trainer properties {get; set;}
// a trainer has an account
public Account Account {get; set;}
}
public class GymOwner
{
public ... some gym owner properties {get; set;}
public Account Account {get; set;}
}
Если ваш дизайн будет, как это, вы бы увидели, что по крайней мере вы бы таблицу владельца тренажерного зала и стол тренера. Но что делать со Счета.
Одним из решений было бы разместить учетную запись в отдельной таблице и добавить что-то к тренеру и владельцу тренажерного зала, чтобы, если у вас есть тренер, вы знаете, какой элемент в таблице учета принадлежит данному конкретному тренеру.
Этот метод обычно не используется в этой конструкции. Если объект A и объект B имеют отношение один к одному: один A принадлежит одному B, а один B принадлежит одному A, то на самом деле их можно поместить в одну таблицу. Если вы используете инфраструктуру сущности и определили классы выше, свойства учетной записи будут добавляться в виде столбцов в таблицу тренеров и в виде столбцов в таблицу владельца тренажерного зала. Преимущество в том, что получение информации о тренере происходит быстрее, так как это предполагает доступ только к одной таблице.
О главных ключах. Каждый элемент в каждой таблице должен иметь ровно один первичный ключ. Это свойство, которое идентифицирует объект. Если у вас есть ключ, у вас очень быстрый доступ ко всем другим свойствам. Чтобы облегчить вам понимание роли учетной записи, я оставил Id в своем исходном коде.
Но теперь, когда мы решили, что было бы лучше, чтобы владельцы Тренеры и Тренажерщики имели учетную запись, там было бы два: Тренеры и GymOwners. Это единственные элементы, которые имеют первичный ключ. Занятия будут следующими:
public class Account
{
public string UserName {get; set;}
public string Password {get; set;}
public AccessLevel AccessLevel {get; set;}
}
public class Trainer
{
public int Id {get; set;}
public .. some trainer properties {get; set;}
// a trainer has an account
public Account Account {get; set;}
}
public class GymOwner
{
public int Id {get; set;}
public ... some gym owner properties {get; set;}
public Account Account {get; set;}
}
Обратите внимание, что для учетной записи нет таблицы, поэтому учетной записи не нужен ключ.
Так что, когда вам нужен внешний ключ
Если тренер не будет иметь один счет, но несколько счетов, может быть много счетов, как правило, называется совокупность счетов, то мы не можем сохранить учетные записи как столбцы в таблице тренера. Мы должны будем поместить все счета Тренера в отдельную таблицу и рассказать каждой учетной записи, к которой он принадлежит. Учетная запись получает внешний ключ к первому ключу тренера, которому он принадлежит.
В терминах базы данных это называется отношением «один ко многим»: у одного тренера есть много учетных записей.
В рамках сущности классы будут, как:
public class Account
{
public int Id {Get; set;}
public int TrainerId {get; set;}
public string UserName {get; set;}
public string Password {get; set;}
public AccessLevel AccessLevel {get; set;}
}
public class Trainer
{
public int Id {get; set;}
public .. some trainer properties {get; set;}
// a trainer has an account
public virtual ICollection<Account> Accounts {get; set;}
}
public class MyDbContext : DbContext
{
public DbSet<Trainer> Trainers {get; set;}
public DbSet<Account> Accounts {get; set;}
}
Обратите внимание, что из-за счета имеют свою собственную таблицу он получил первичный ключ. Кроме того, он также получил внешний ключ в собственности TrainerId.
Я также добавил класс, полученный из DbContext, для доступа к таблицам. Пока не знаю, что у меня есть только таблицы с тренерами и таблицами со счетами. Каждая таблица называется DbSet, тип DbSet сообщает структуру сущности о столбцах в таблице.
Поскольку Trainer имеет виртуальный ICollection of Accounts, инфраструктура сущности знает, что между тренером и учетной записью существует отношение «один ко многим», а из-за наследования TrainerId структура сущности знает, что TrainerId является внешним ключом к первичному ключа трейнера, к которому принадлежит учетная запись.
Так что если у вас есть идентификатор тренера, вы получите все аккаунты этого тренера, используя следующие операторы Linq:
int trainerId = GetMyTrainerId();
IEnumerable<Account> accountsOfTrainer = dbContext.Accounts
.Where(account => account.TrainerId == trainerId);
Из коллекции счетов, принять все записи, в которых свойство TrainerId равняется trainerId
Итак, теперь вы знаете, как создать первичный ключ и указать на него внешний ключ.
А как насчет владельцев тренажерных залов? Если владелец тренажерного зала имеет только одну учетную запись, просто позвольте ей иметь один аккаунт (состав). Но что, если ваш владелец спортзал также имеет коллекцию учетных записей.
Если вы просто добавили учетные записи владельца тренажерного зала в таблицу счетов, то у вас возникают проблемы. К какому идентификатору относится внешний ключ? К первичному ключу в таблице Тренера или в таблице владельцев тренажеров?
Самый безопасный способ - создать GymOwnersAccount и TrainingersAccount. У каждого будет своя таблица с внешним ключом. У GymOwnersAccount будет внешний ключ к таблице GymOwners, а у TrainersAccount будет внешний ключ для таблицы тренеров.
Здесь вы также можете принять решение о том, что учетная запись GymOwners должна иметь учетную запись, но кажется более естественным сказать, что учетная запись GymOwners является особым типом учетной записи и, следовательно, происходит из учетной записи.
public class Account
{
public string UserName {get; set;}
public string Password {get; set;}
public AccessLevel AccessLevel {get; set;}
}
public class GymOwnerAccount : Account
{
public int Id {get; set;}
public int GymOwnerId {get; set;}
}
public class TrainerAccount : Account
{
public int Id {get; set;}
public int TrainerId {get; set;}
}
public class Trainer
{
public int Id {get; set;}
public .. some trainer properties {get; set;}
// a trainer has an account
public virtual ICollection<Account> Accounts {get; set;}
}
public class GymOwner
{
public int Id {get; set;}
public ... some gym owner properties {get; set;}
public virtual ICollection<Account> Accounts {get; set;}
}
public class MyDbContext : DbContext
{
public DbSet<Trainer> Trainers {get; set;}
public DbSet<Account> GymOwnerAccounts {get; set;}
public DbSet<Account> TrainerAccounts {get; set;}
}
Есть и другие решения можно, например, дать каждому счету два внешних ключей, один для владельцев тренажерного зала и один для инструкторов, где вы всегда должны установить один внешний ключ к 0. Легко видеть, что это может приводят к проблемам технического обслуживания, в то время как это не дает вам никаких преимуществ, поэтому я бы посоветовал придерживаться отдельных таблиц для GymOwnerAccounts и TrainerAccounts.
Теперь, когда я вошел в область наследования в базе данных, есть множество элементов, которые вы можете настроить. Статья, которая помогла мне понять концепцию сущности, а также то, как классы, наследование, состав передается в базы данных, - Entity Framework Code First
У вас здесь много проблем. Первый - базовый [дизайн базы данных] (http://sqlmag.com/database-performance-tuning/sql-design-why-you-need-database-normalization) и выяснение ваших объектов. Во-вторых, у вас есть проблема безопасности. У .NET есть некоторые хорошие встроенные функции, такие как [Identity] (https://www.asp.net/identity/overview/getting-started/introduction-to-aspnet-identity), которые могут помочь. –
Я просто делаю проект для себя и не ставил их в Интернете. Если проблемы с безопасностью связаны с хэшированными паролями, а что нет, я планировал это, но я еще не сделал этого, поскольку я больше фокусируюсь на получении более четкого изображения, а затем реализую его после этого, я позабочусь о других нюансах, таких как безопасности и т. д. Мне просто нужна грубая форма, в которой я могу полировать. – john
ОК, начните со своих основных объектов: учетная запись, тренажерный зал, пользователь, тренер. Первичные ключи зависят от вас - я предпочитаю [суррогатные ключи] (http://stackoverflow.com/questions/20052799/surrogate-key-vs-natural-key-for-ef), но вы можете использовать естественные ключи, такие как UserName если хочешь. Затем сделайте связь между этими таблицами, и EF выполнит фоновое задание. –