中央ID表的最佳代码优先方法

本文关键字:方法 代码 最佳 ID 中央 | 更新日期: 2023-09-27 18:18:13

我们使用实体框架代码优先为这个项目的数据库。

我们的需求需要一个中央'Resource'表,其中包含ResourceId (uniqueidentifier NOT NULL DEFAULT (newsequentialid()))的单列。各种表将使用这个表作为它们的ID。

Profile - ProfileId (uniqueidentifier NOT NULL)Organization - OrganizationId (uniqueidentifier NOT NULL)文档=文档id (uniqueidentifier NOT NULL)

因此,如果我创建一个新的概要文件记录,我将创建一个新的资源记录,并使用顺序创建的Guid作为新的概要文件记录的ID。

这样做的原因是为了防止Profile中的Id作为组织的Id出现。(我知道这很可能是不可能的,但不是不可能的。)

现在我们用这样的关系来定义它:

public class Resource : BaseEntity
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid ResourceId { get; set; }
    public virtual Profile Profile_ProfileId { get; set; }
    //...
}
public class Profile : BaseEntity, IAuditableEntity
{
    [Key]     
    public Guid ProfileId { get; set; }
    public virtual Resource Resource { get; set; }
    //...
}
public class ProfileMapping : EntityTypeConfiguration<Profile>
{
    public ProfileMapping()
    {
        //Primary key 
        HasKey(t => t.ProfileId);
        //Constraints 
        Property(t => t.ProfileId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
        //...
        ToTable("Profile");
        //Create Relation
        HasRequired(t => t.Resource).WithOptional(t => t.Profile_ProfileId);
    }
}

然后,当我们创建一个新的Profile时,我们这样做(db是我们的DBContext的一个实例):

var res = new Resource();
db.Resource.Add(res);
var newProfile = new Profile{
    ProfileId = res.ResourceId,
    IsActive = true
};
db.Profile.Add(newProfile);

然而,我想知道,我们可以定义我们的类/模型从资源继承,并得到更好的结果吗?
你们有人用过这样的数据库结构吗?

中央ID表的最佳代码优先方法

实际上,由于ProfileIdOrganizationId的guid是在同一数据库服务器上生成的,因此可以100%保证它们是唯一的。我假设您将让数据库服务器生成guid。

guid如果在不同的机器上生成,可能有机会(非常小的机会)发生冲突。

不管怎样,下面是对你问题的直接回答:

你可以这样做:

public class Resource
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid ResourceId { get; set; }        
}
public class Profile
{
    [Key]
    [ForeignKey("Resource")]
    public Guid ProfileId { get; set; }
    public Resource Resource { get; set; }
    public string Name { get; set; }
    public Profile()
    {
        Resource = new Resource();
    }
}

注意Profile实体如何在其构造函数中创建Resource实体。还要注意,Profile的主键也是一个外键。

更新:

这是我认为更好的另一个解决方案,这也将在您想要从Resource实体访问Profile实体的情况下工作:

我给Resource实体添加了一个Profile属性:

public class Resource
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid ResourceId { get; set; }
    public virtual Profile Profile { get; set; }
}

配置文件实体:

public class Profile
{
    [Key, ForeignKey("Resource"), DatabaseGenerated(DatabaseGeneratedOption.None)]
    public Guid ProfileId { get; set; }
    public Resource Resource { get; set; }
    public string Name { get; set; }
}

注意,我不再在构造函数中创建Resource对象。

相反,我在保存实体时通过覆盖DbContext上的SaveChanges方法创建它,如下所示:

public class MyContext : DbContext
{
    public DbSet<Resource> Resources { get; set; }
    public DbSet<Profile> Profiles { get; set; }
    public override int SaveChanges()
    {
        foreach (var profile in ChangeTracker.Entries<Profile>()
            .Where(x => x.State == EntityState.Added))
        {
            profile.Entity.Resource = new Resource();
        }
        //Here you also need to do the same thing for other Entities that need a row in the Resources table (e.g. Organizations)
        return base.SaveChanges();
    }
}