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

How to create clustered keys in code first

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

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

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

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

同事class:

public class Colleague
{
    [Key]
    public int ColleagueId { get; set; }

    [Key]
    public virtual Person PersonId { get; set; }
}

人 class:

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

您基本上想要 Person 个实体之间的 many-to-many 关系。为此,您需要一个连接点 table,其中 links 对 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 的 collection:通过向这个 collection 添加一个实体,你不仅 link这个人给his/her同事,也建立逆向关系。我还添加了一个辅助方法,以便您可以轻松添加关系。

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

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

(我把用来表示同事collection的名字属性复数化了。

EF Code First 然后应该创建一个 Person table 和一个额外的 Discriminator 列,用于区分 PersonColleague 实体。

再考虑一下,我什至不确定您是否需要单独的 Colleague 实体。你可能会逃脱这个:

public class Person
{
    ...
    public virtual ICollection<Person> Colleagues { get; set; }
}

注意 ICollection<Person> 而不是 ICollection<Colleague>

我使用 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 数字) .当然你可以根据自己的类型适配。