如何首先在代码中创建聚集键
How to create clustered keys in code first
一个人可以有很多同事,一个同事就是一个人。是否可以在 ColleagueId
和 PersonId
上创建聚簇键?
好吧,我不太确定,但同事 class 只是因为数据库应该理解与 Person
的连接。所以,实际上我不需要 Colleague
class。我怎样才能让数据库理解 Person
有一个 Colleagues
的列表,即 Person
?
在程序中,我们可以创建Persons
,然后我们应该可以将其他Persons
添加到Colleagues
的Persons
列表中!
我的解释感觉很模糊,但我不知道如何用其他方式解释它。
同事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
列,用于区分 Person
和 Colleague
实体。
再考虑一下,我什至不确定您是否需要单独的 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 数字) .当然你可以根据自己的类型适配。
一个人可以有很多同事,一个同事就是一个人。是否可以在 ColleagueId
和 PersonId
上创建聚簇键?
好吧,我不太确定,但同事 class 只是因为数据库应该理解与 Person
的连接。所以,实际上我不需要 Colleague
class。我怎样才能让数据库理解 Person
有一个 Colleagues
的列表,即 Person
?
在程序中,我们可以创建Persons
,然后我们应该可以将其他Persons
添加到Colleagues
的Persons
列表中!
我的解释感觉很模糊,但我不知道如何用其他方式解释它。
同事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
列,用于区分 Person
和 Colleague
实体。
再考虑一下,我什至不确定您是否需要单独的 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 数字) .当然你可以根据自己的类型适配。