【问题标题】:Database 3 types of users数据库 3 类用户
【发布时间】:2017-01-10 20:06:32
【问题描述】:

我真的很困惑。我只是找不到专为新手或傻瓜设计的指南,我所得到的只是我忘记的高级或至少学过的技术知识。 (当我还在学习时,对数据库的了解并不多)

所以我发布了一张我制作的粗略轮廓的图片,我已经做了几个小时,但我的犹豫不决没有去任何地方,每次我觉得自己走在正确的轨道上时,我都会怀疑自己。

无论如何,我应该如何设计表格?

假设有 3 种类型的帐户。 1 代表普通,2 代表教练,3 代表健身房。

我使用帐户表来获取正在登录的帐户的访问级别。所以我对此感到非常困惑。我很确定所有表都需要有一个主键。所以我决定每个人都在所有桌子上都有 id。

像 userid、trainerid、gymid。

那么我如何将它们 FK 到帐户的表中?我是否将所有 3 个都添加为 FK?如果是普通用户,那么 trainerid(FK) 和gymid(FK) 将为空,FK 为 null 是否可以接受?

accounts 表也有一个 accountid(PK),甚至不确定它是否有用,或者因为我只需要检查 accounts 表的 accesslevel col(我可能会知道我何时深入参与其中稍后现在我只是无法在帐户表上看到 PK 的使用,除了每个表都需要一个 PK 的事实。

所以我在想,我应该只使用用户名作为外键吗?但是普通的唯一列可以是外键吗?还是需要将它们设置为主键?

另外,还有一个问题,关于 3 种类型的帐户,它们基本上都有一个个人资料,我是否应该制作另一个连接到他们的名为个人资料的表格?(每个用户类型的课程,如 user_profile、trainer_profile、gym_profile) .

【问题讨论】:

  • 那里有很多问题。第一个是基本的database design 并找出你的实体。其次,您有安全问题。 .NET 有一些不错的内置功能,例如 Identity,可以提供帮助。
  • 我只是为自己做一个项目,而不是把它们放到网上。如果安全问题与散列密码有关,我正在计划,但我还没有这样做,因为我更专注于获得更清晰的图像,然后实施它们,然后我会处理其他细微差别,例如安全等。我只想要一个可以打磨的粗略形式。
  • 好的,从您的基本实体开始:帐户、健身房、用户、培训师。主键由你决定——我更喜欢surrogate keys,但如果你愿意,你可以使用像 UserName 这样的自然键。然后在这些表之间建立关系,EF 将完成后台工作。

标签: mysql database entity-framework


【解决方案1】:

也许问题之一是您立即开始考虑表格、ID 和外键等。如果您考虑对象及其彼此之间的关系,通常会容易得多。

阅读您的图片有点困难。从文本中我收集到您有帐户的概念,显然有三种类型的帐户:普通帐户、培训师和健身房所有者。这些账户有区别吗?健身房老板有普通用户没有的属性吗?还是只是某种身份证明。

从您的绘图看来,普通用户具有用户名、密码和访问级别。培训师也有这些属性吗?

如果是这样,那么在普通的面向对象设计中,你会说它是一个聚合:培训师、普通人和健身房老板都有一个用户名、一个密码和一个访问级别。聚合也经常被称为组合。有一点点不同,但对于本次讨论来说,这并不重要。

除了聚合/组合(对象有一个帐户),您还可以考虑继承:对象是一个帐户:培训师帐户、健身房所有者帐户和普通帐户是所有不同类型的帐户的对象,有一个用户名称、密码和访问级别。

在此示例中,聚合(培训师有一个帐户)或继承(培训师帐户是一个帐户)之间没有太大区别。通常建议是倾向于聚合而不是继承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,那么实际上它们可以放在一张表中。如果您使用实体框架并且您已经定义了上述类,则帐户属性将作为列添加到 trainer 表和作为列添加到 gym owner 表。优点是获取有关培训师的信息更快,因为这将只涉及访问一个表。

关于主键。每个表中的每个元素都应该只有一个主键。这是标识对象的属性。如果您有密钥,您可以非常快速地访问所有其他属性。为了让您更容易理解 Account 的作用,我在原始代码中省略了 Id。

但既然我们已经决定最好让 Trainers 和 GymOwners 拥有一个帐户,那么将有两个表:Trainers 和 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;}
}

请注意,Account 没有表,因此 Account 不需要密钥。

那么你什么时候需要外键

如果一个 Trainer 不会有一个帐户,而是几个帐户,可能是很多帐户,通常称为帐户集合,那么我们不能再将帐户保存为 Trainer 表中的列。我们必须将 Trainer 的所有帐户放在一个单独的表中,并告诉每个帐户它属于哪个 trainer。该帐户获得了一个外键,用于他所属的培训师的主键。

在数据库术语中,这称为一对多关系:一个培训师有多个帐户。

对于实体框架,类应该是这样的:

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;}
}

请注意,由于 Account 有自己的表,因此它已获得主键。 除此之外,它还在属性 TrainerId 中获得了一个外键。

我还添加了一个派生自 DbContext 的类来访问这些表。直到知道我只有带有培训师的表格和带有帐户的表格。每个表称为一个 DbSet,DbSet 的类型通知实体框架表中的列。

因为 Trainer 有一个虚拟的 ICollection 的 Accounts,实体框架知道 Trainer 和 Account 之间是一对多的关系,并且由于 namer TrainerId,实体框架知道 TrainerId 是主键的外键该帐户所属的培训师。

因此,如果您有培训师的 id,您可以使用以下 Linq 语句获取该培训师的所有帐户:

int trainerId = GetMyTrainerId();
IEnumerable<Account> accountsOfTrainer = dbContext.Accounts
    .Where(account => account.TrainerId == trainerId);

从 Accounts 集合中,获取属性 TrainerId 等于 trainerId 的所有记录

所以现在您知道如何设计主键并让外键指向它了。

但是健身房老板呢?如果健身房老板只有一个账户,就让它有一个账户(组成)。但是,如果您的健身房所有者也有一系列帐户怎么办。

如果您只是将健身房所有者帐户添加到帐户表中,那么您会遇到麻烦。外键指向哪个 Id?要在 Trainer 表或 Gym Owners 表中作为主键?

最安全的方法是创建 GymOwnersAccount 和 TrainersAccount。他们每个人都有自己的带有外键的表。 GymOwnersAccount 将具有 GymOwners 表的外键,TrainersAccount 将具有 trainers 表的外键。

在这里,您还可以决定让 GymOwners 帐户拥有一个帐户,但更自然地说 GymOwners 帐户是一种特殊类型的帐户,因此派生自 Account。

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

【讨论】:

  • 我的大脑刚刚被炸了,我可能需要睡觉了。我想澄清一下这 3 种帐户类型。我打算做一个项目,你可以在网上找到健身房,当你在网上找到健身房时,你在这些健身房注册(在线或 irl 付款)注册后你可以选择有培训师可供选择的项目,也可以从一个项目中选择到下一个,培训师将跟踪您的进度,如果您完成了,系统将推荐进一步的程序。就像技能树一样。在任何情况下,每种类型的用户都会访问差异函数。
  • 拥有个人资料的用户是给定的,健身房和培训师也是如此。这就是为什么我很困惑。我只是无法专心设计我的数据库的粗略轮廓,即使没有细节,如果我只有一个粗略的轮廓,至少我有一个编码方向。
  • 所以你有一个班级健身房。一个健身房有很多客户(一对多)。一个健身房也有很多教练,还有很多健身房项目。每个健身计划在一周内进行多次(健身课?)每个健身课都有一个开始时间,一个停止时间,并由一名(或更多)健身教练带领。每个健身课程都有零个或多个客户参加。你又看到了:在课堂上思考,而不是在表格中思考。在了解了类及其关系(HAS / IS、一对多或一对一)之后,您可以大致了解类和关系,您知道您需要哪些表以及哪些主键/外键跨度>
猜你喜欢
  • 2017-10-28
  • 2014-12-17
  • 1970-01-01
  • 1970-01-01
  • 2011-02-04
  • 1970-01-01
  • 2017-05-24
  • 1970-01-01
  • 2012-12-04
相关资源
最近更新 更多