实体框架:每个具体类型的表和跨表的唯一 ID
我有几个表仅共享一些导航属性和 ID。 我认为每个具体类型继承的表在这里会很有趣..(?) 它看起来像这样:
联系人(基础,摘要,未映射)
- 联系方式
- 导航属性到其他表(电子邮件、电话等)
人员:联系人(映射到具有各种属性 + ContactID 的表人员)
- 各种属性
公司:联系人(映射到具有各种属性的表公司 + ContactID)
- 各种属性
现在,要使其正常工作,主键 (contactID) 在所有表中应该是唯一的。 则有 2 个选项:
- GUID(不是粉丝)
- 生成身份的附加数据库表(仅具有 ContactID 字段,派生表具有 FK),这不会在 EF 中映射。
这个设置可行吗? 另外,ObjectContext 中会发生什么? EF 在调用 SaveChanges 之前生成什么样的临时密钥?它在对象之间是唯一的吗?
感谢您的任何想法。 麦克风。
I have a few tables that share only a few navigation properties and an ID.
I think Table per Concrete type inheritance would be interesting here.. (?)
It looks something like this :
Contact (Base, Abstract, not mapped)
- ContactID
- navigation properties to other tables (email, phone, ..)
Person : Contact (mapped to table Person with various properties + ContactID)
- various properties
Company : Contact (mapped to table Company with various properties + ContactID)
- various properties
Now for this to work, the primary key (contactID) should be unique across all tables.
2 options then:
- GUIDs (not a fan)
- an additional DB table generating identities (with just a ContactID field, deriving tables have FK), this would not be mapped in EF.
Is this setup doable ?
Also, what will happen in the ObjectContext ? What kind of temporary key does EF generate before calling SaveChanges ? Will it be unique across objects ?
Thanks for any thoughts.
mike.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我们使用以下数据库设计的类似结构:
ContactEntity
ContactPossibility
地址
电话
人员
公司
这导致实体模型分为两个抽象类:ContactEntity (CE) 和 ContactEntity (CE)。 ContactPossibility (CP) 和多个派生类(Address=CP、Email=CP、Person=CE、Company=CE)。抽象类和派生类(数据库中的行;)共享相同的唯一标识符,因为我们在派生类中使用 ID 字段,该字段是抽象类主键的外键。我们为此使用 Guid,因为我们的软件需要离线(不连接到主数据库)正常运行,并且我们必须顺利处理同步问题。另外,Guid 的问题是什么?
实体框架确实很好地支持了这种数据库/类设计,我们从这种设计中得到了很多乐趣。
建议的设置非常可行!
ObjectContext 运行良好,并且可以毫不费力地插入、更新和删除派生类的正确表。临时钥匙?如果您使用派生类的 ID 模式(该模式既是抽象类的主键又是外键),则不需要它们。通过 Guid,您可以非常确定它在对象中是唯一的。
此外:从CP到CE的foreignKey将为每个CE(个人、公司、用户等)提供可跟踪的ContactPossibilities集合。这真的很酷而且方便。
希望这有帮助...
We use a similiar construction with the folowing db design:
ContactEntity
ContactPossibility
Address
Telephone
Person
Company
This results in the entity model in two abstract classes: ContactEntity (CE) & ContactPossibility (CP) and multiple derived classes (Address=CP, Email=CP, Person=CE, Company=CE). The abstract and derived classes (rows in the db ;) share the same unique identifier, because we use an ID field in derived classes that's a foreign key to the primary key of the abstract class. And we use Guid's for this, because our software has the requirement to function properly off-line (not connected to the main database) and we have to deal smoothly with synchronisation issues. Also, what's the problem with Guid's?
Entity Framework does support this db / class design very good and we have a lot of pleasure from this design.
The proposed setup is very very doable!
The ObjectContext acts fine and will insert, update and delete the right tables for derived classes without effort. Temporary keys? You don't need them if you use the pattern of an ID for derived classes that is both primary key and foreign key to the abstract class. And with Guid's you can be pretty sure that's unique across objetcs.
Furthermore: The foreignKey from CP to CE will provide every CE (Person, Company, User, etc.) with a trackable collection of ContactPossibilities. Which is real cool and handy.
Hope this helps...
(评论部分没有足够的空间)
我一直在运行一些测试。
问题是,只要您只指定要查询的子类型(例如您的情况下的“地址”),就可以了。
但是,如果您查询基本类型(即使您不需要子类型信息),例如。仅ContactPossibility.ID,生成的SQL将UNION所有子类型表。
因此,查询“可追踪”的 ContactPossibilities 集合可能会产生性能问题。
我尝试通过取消映射基本实体并将继承的实体拆分为自己的表+公共表来解决此问题,基本上将 TPT 转换为 TPC :从概念角度来看,这工作得很好(经过大量 edmx 编辑后)。
直到我意识到这是愚蠢的...:) 事实上,在这种情况下,您将始终需要联合所有基础表来查询公共数据...
(虽然我不确定本文末尾描述的情况,但没有继续测试它)
所以我想,因为大多数情况下我需要查询特定类型(人、公司、地址、电话、 ..),现在一切都会好的,希望 MS 能够在 EF4.5 中提供修复。
所以我在查询时必须小心,另一个有趣的例子:
假设您想选择一个人,然后查询他的地址,例如(尝试遵循您的命名):
var person = 来自 context.ContactEntities.OfType-Person-() 中的 b
其中 b.FirstName.StartsWith("X")
选择b;
var 地址 = 来自 context.ContactPossibilities.OfType-Address-()
其中 **a.ContactEntity == person.FirstOrDefault()**
选择一个;
这将在联系人派生实体的所有表之间产生一个并集,并产生性能问题:生成的 SQL 采用 ContactPossibility 表并联接到 ContactPossibilityID 上的地址,然后联接与基本联系人表联接的所有联系人派生表的并集< /b>,最后加入过滤的 Person 表之前。
但是,请考虑以下替代方案:
var person = 来自 context.ContactEntities.OfType-Person-() 中的 b
其中 b.FirstName.StartsWith("X")
选择b;
var 地址 = 来自 context.ContactPossibilities.OfType-Address-()
其中 **a.ContactID == person.FirstOrDefault().ID**
选择一个;
这将正常工作:生成的 SQL 获取 ContactPossibility 表并连接到 ContactPossibilityID 上的 Address,然后连接过滤后的 Person 表。
麦克风。
(not enough space in the comments section)
I've been running some tests.
The thing is you're OK as long as you ONLY specify the subtype you're querying for (ex. 'Address' in your case).
But if you query for the base type (even if you don't need the subtypes info), ex. only ContactPossibility.ID, the generated SQL will UNION all subtype tables.
So querying your 'trackable' collection of ContactPossibilities can create a performance problem.
I tried to work around this by unmapping the base entity and split the inherited entities to their own table + the common table, basically transforming the TPT into TPC : this worked fine from a conceptual perspective (after a lot of edmx editing).
Until I realized this was stupid... :) Indeed in that case you will always need to Union all underlying tables to query for the common data...
(Though I'm not sure in the case described at the end of this post, didn't pursue to test it)
So I guess, since mostly I will need to query for a specific type (person, company, address, phone,..), it's gonna be OK for now and hoping MS will come with a fix in EF4.5.
So I'll have to be careful when querying, another interesting example :
Let's say you want to select a person and then query for his address, something like (tried to follow your naming) :
var person = from b in context.ContactEntities.OfType-Person-()
where b.FirstName.StartsWith("X")
select b;
var address = from a in context.ContactPossibilities.OfType-Address-()
where **a.ContactEntity == person.FirstOrDefault()**
select a;
this will produce a Union between all the tables of the Contact derived entities, and performance issues : generated SQL takes ContactPossibility table and joins to Address on ContactPossibilityID, then joins a union of all Contact derived tables joined with the base Contact table, before finally joining a filtered Person table.
However, consider the following alternative :
var person = from b in context.ContactEntities.OfType-Person-()
where b.FirstName.StartsWith("X")<BR>
select b;
var address = from a in context.ContactPossibilities.OfType-Address-()
where **a.ContactID == person.FirstOrDefault().ID**
select a;
This will work fine : generated SQL takes ContactPossibility table and joins to Address on ContactPossibilityID, and then joins the filtered Person table.
Mike.