如何首先在代码中创建集群键

Posted

技术标签:

【中文标题】如何首先在代码中创建集群键【英文标题】:How to create clustered keys in code first 【发布时间】:2015-01-22 09:51:21 【问题描述】:

一个人可以有很多同事,一个同事就是一个人。是否可以在ColleagueIdPersonId 上创建集群键?

好的,我不太确定,但 Colleague 类只是因为数据库应该理解与Person 的连接。所以,实际上我不需要Colleague 类。我该怎么做才能让数据库知道Person 有一个Colleagues 列表,即Person

在程序中,我们可以创建Persons,然后我们应该可以将其他Persons添加到PersonsPersons列表中Colleagues

我的解释感觉很模糊,但我不知道如何以任何其他方式解释它。

同事班:

public class Colleague

    [Key]
    public int ColleagueId  get; set; 

    [Key]
    public virtual Person PersonId  get; set; 

人物类:

public class Person

    public int Id  get; set; 
    public string Name  get; set; 
    public byte[] Image  get; set; 

    public virtual ICollection<Conversation> Conversations  get; set; 

    public virtual ICollection<Colleague> Colleague  get; set; 


    public Person()
    
        Conversations = new List<Conversation>();
        Colleague = new List<Colleague>();
    

【问题讨论】:

【参考方案1】:

我使用 OrmLite v3(不支持复杂主键)。我在那里使用的解决方法是创建一个新属性,它是两个键的组合,我将其用作键:

public class Colleague

    public int ColleagueId  get; set; 
    public int PersonId  get; set; 

    [Key]
    public string CombinedId 
        get  return ColleagueId.ToString() + PersonId.ToString(); 
    

我使用string 类型来避免获得两个int 值的总和(这可能导致键冲突,尽管它并不完全安全,具体取决于 int 数字)。当然你可以根据自己的类型进行调整。

【讨论】:

【参考方案2】:

您基本上想要Person 实体之间的多对多关系。为此,您需要一个联结表来链接成对的Person 实体。如果我们称这个实体为WorkRelationship

class WorkRelationship

    [Key]
    [Column(Order = 1)]
    [ForeignKey("Myself")]
    public int MyselfId  get; set; 

    public virtual Person Myself  get; set; 

    [Key]
    [Column(Order = 2)]
    [ForeignKey("Colleague")]
    public int ColleagueId  get; set; 

    public virtual Person Colleague  get; set; 

然后我们像这样修改Person

class Person

    public int Id  get; set; 
    public string Name  get; set; 

    [InverseProperty("Myself")]
    public virtual ICollection<WorkRelationship> WorkRelationships  get; set; 

    public void AddWorkRelationship(Person colleague)
    
        if (WorkRelationships == null)
        
            WorkRelationships = new List<WorkRelationship>();
        

        WorkRelationships.Add(new WorkRelationship  Myself = this, Colleague = colleague );
    

所以你可以看到Person 现在有一个WorkRelationships 的集合:通过向这个集合中添加一个实体,你不仅可以将此人链接到他/她的同事,还可以创建反向关系。我还添加了一个辅助方法,以便您可以轻松添加关系。

这是一个非常基本的数据库上下文类,可用于管理这些实体:

sealed class MyContext : DbContext

    public DbSet<Person> People  get; set; 
    public DbSet<WorkRelationship> WorkRelationships  get; set; 

    public IEnumerable<Person> GetColleagues(int personId)
    
        List<WorkRelationship> relationships =
            WorkRelationships
            .Include(x => x.Myself)
            .Include(x => x.Colleague)
            .Where(x => x.MyselfId == personId || x.ColleagueId == personId)
            .ToList();

        foreach (WorkRelationship relationship in relationships)
        
            if (relationship.Myself.Id == personId)
            
                yield return relationship.Colleague;
            
            else if (relationship.Colleague.Id == personId)
            
                yield return relationship.Myself;
            
        
    

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
        modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
        modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();
    

我还为此添加了一个辅助方法,它将检索给定人员的同事。

我们现在可以创建一个简单的测试程序来插入和查询人员:

static void Main(string[] args)

    var alice = new Person  Name = "Alice" ;
    var bob = new Person  Name = "Bob" ;
    var colin = new Person  Name = "Colin" ;
    var davina = new Person  Name = "Davina" ;

    alice.AddWorkRelationship(bob);
    alice.AddWorkRelationship(colin);

    bob.AddWorkRelationship(davina);

    using (var db = new MyContext())
    
        db.People.AddRange(new[]  alice, bob, colin, davina );
        db.SaveChanges();
    

    using (var db = new MyContext())
    
        Console.WriteLine("Bob works with:");
        foreach (Person colleague in db.GetColleagues(bob.Id))
        
            Console.WriteLine(colleague.Name);
        
    

    Console.ReadLine();


原始答案如下(包含在上下文中)

如果Colleague is-a Person,那么你应该这样建模:

public class Colleague : Person

    // don't need any other properties based on what you've posted


public class Person

    public int Id  get; set; 
    public string Name  get; set; 
    public byte[] Image  get; set; 
    public virtual ICollection<Conversation> Conversations  get; set; 
    public virtual ICollection<Colleague> Colleagues  get; set; 

(我已将用于保存同事集合的属性名称复数)。

然后,EF Code First 应该创建一个单独的 Person 表,其中包含一个额外的 Discriminator 列,用于区分 PersonColleague 实体。

再想一想,我什至不确定您是否需要单独的 Colleague 实体。你可能会侥幸逃脱:

public class Person

    ...
    public virtual ICollection<Person> Colleagues  get; set; 

注意ICollection&lt;Person&gt; 而不是ICollection&lt;Colleague&gt;

【讨论】:

所以如果我使用这个。我可以从数据库中加载一个拥有Colleagues 列表的Person 吗? db.People.Where(x =&gt; x.Colleagues.Count &gt; 0) 这样的东西应该会返回一个Person 实体列表,这些实体已经分配了同事(我没有测试过,但我认为它应该可以工作)。 好吧,我不太确定,但Colleague 类之所以存在,是因为数据库应该理解与Person 的连接。 也许你可以在你的问题中添加一些细节来解释你打算用Colleague实体做什么?目前,根据您所说,同事只是一个与另一个人有关系的人,大概是因为他们一起工作。我认为你不需要一个单独的实体。

以上是关于如何首先在代码中创建集群键的主要内容,如果未能解决你的问题,请参考以下文章

如何首先在 EF 代码中创建持久计算列?

如何使用 EF 核心在 SQLite 中创建自动增量列?

如何使用 EF 核心在 SQLite 中创建自动增量列?

首先使用代码在 MySQL 中创建 NVARCHAR 列?

如何使用 VBA 在 ms 访问表单中创建自定义自动编号? [关闭]

无法在现有Apache Ignite单节点集群中创建缓存