如何首先在代码中创建集群键
Posted
技术标签:
【中文标题】如何首先在代码中创建集群键【英文标题】:How to create clustered keys in code first 【发布时间】:2015-01-22 09:51:21 【问题描述】:一个人可以有很多同事,一个同事就是一个人。是否可以在ColleagueId
和PersonId
上创建集群键?
好的,我不太确定,但 Colleague 类只是因为数据库应该理解与Person
的连接。所以,实际上我不需要Colleague
类。我该怎么做才能让数据库知道Person
有一个Colleagues
列表,即Person
?
在程序中,我们可以创建Persons
,然后我们应该可以将其他Persons
添加到Persons
的Persons
列表中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
列,用于区分 Person
和 Colleague
实体。
再想一想,我什至不确定您是否需要单独的 Colleague
实体。你可能会侥幸逃脱:
public class Person
...
public virtual ICollection<Person> Colleagues get; set;
注意ICollection<Person>
而不是ICollection<Colleague>
。
【讨论】:
所以如果我使用这个。我可以从数据库中加载一个拥有Colleagues
列表的Person
吗?
像db.People.Where(x => x.Colleagues.Count > 0)
这样的东西应该会返回一个Person
实体列表,这些实体已经分配了同事(我没有测试过,但我认为它应该可以工作)。
好吧,我不太确定,但Colleague
类之所以存在,是因为数据库应该理解与Person
的连接。
也许你可以在你的问题中添加一些细节来解释你打算用Colleague
实体做什么?目前,根据您所说,同事只是一个与另一个人有关系的人,大概是因为他们一起工作。我认为你不需要一个单独的实体。以上是关于如何首先在代码中创建集群键的主要内容,如果未能解决你的问题,请参考以下文章