【问题标题】: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>();
    }
}

【问题讨论】:

    标签: c# code-first data-annotations


    【解决方案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实体做什么?目前,根据您所说,同事只是一个与另一个人有关系的人,大概是因为他们一起工作。我认为你不需要一个单独的实体。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-21
      相关资源
      最近更新 更多