数据库3类型的用户

时间:2017-01-10 20:06:32

标签: mysql database entity-framework

我真的很困惑。我只是找不到专为新手或假人设计的指南,所有我得到的都是先进或至少学到的技术,我忘记了。 (当我还在学习的时候,数据库并不是很大)

rought outline

所以我发布了一张粗略轮廓的图片,我已经在这里拍了好几个小时,但是我的犹豫不决不会去任何地方,每当我觉得我在正确的轨道上时,我都会猜错。

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

比如说有3种类型的帐户。 1表示正常,2表示训练员,3表示体操运动员。

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

像userid,trainerid,gymid一样。

那我怎么把他们放到帐户的桌子上呢?我将所有3作为FK添加?如果它是普通用户那么训练师(FK)和体操(FK)将是空的,甚至可以接受FK为空?

帐户表也有一个accountid(PK),甚至不确定它是否有用,或者因为我只需要检查帐户表的访问级别col(我可能知道我什么时候开始)我现在深深卷入其中,我只是看不到在账户表上使用PK,除了你需要每个表的PK这个事实。)

所以我想,我应该只使用用户名作为外键吗?但正常的独特cols可以是外键吗?或者是否需要将它们设置为主键?

另外,关于3种类型的帐户的其他问题,它们基本上都有一个配置文件,我应该创建另一个连接到它们的名为profile的表吗?(每个用户类型的一个,如user_profile,trainer_profile,gym_profile) 。

1 个答案:

答案 0 :(得分:0)

也许其中一个问题是你立即开始考虑表和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,那么实际上它们可以放入一个表中。如果您使用实体框架并且已经定义了上述类,则帐户属性将作为列添加到培训师表中,并作为列添加到健身房所有者表中。优点是获取有关培训师的信息更快,因为这只涉及访问一个表。

关于主键。每个表中的每个元素都应该只有一个主键。这是标识对象的属性。如果您有密钥,则可以非常快速地访问所有其他属性。为了让您更容易理解帐户的作用,我在原始代码中遗漏了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;}
}

请注意,帐户没有表格,因此帐户不需要密钥。

那么什么时候需要外键

如果培训师没有一个帐户,但有多个帐户,可能是很多帐户,通常称为帐户集合,那么我们就不能再将帐户保存为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 of Accounts,实体框架知道Trainer和Account之间存在一对多关系,并且由于名称TrainerId,实体框架知道TrainerId是主键的外键该帐户所属的培训师。

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

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

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

现在你知道如何设计主键并让外键指向它。

但是体育馆老板呢?如果健身房所有者只有一个帐户,只需让它拥有一个帐户(组合)。但是如果你的健身房老板也有一系列帐户呢。

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

最安全的方法是创建GymOwnersAccount和TrainersAccount。他们每个人都有自己的外键表。 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