实体框架4每层次表 - 如何定义儿童的导航属性? [英] Entity Framework 4 Table Per Hierarchy - How To Define Navigational Properties On Children?

查看:240
本文介绍了实体框架4每层次表 - 如何定义儿童的导航属性?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前有一个具有Table Per Type(TPT)的实体框架4.0模型,但是有一些性能问题(很多LOJ / CASE语句),以及两个特定领域领域之间的问题映射(许多我已经决定尝试TPH。



我有一个实体叫做位置抽象,也是所有其他实体的基础。



然后我有国家城市等。 p>

LocationType dicriminator



部分工作正常,但我遇到试图定义导出类型的导航属性的问题。



例如,状态有一个国家,所以我应该可以这样做:

  var state = _ctx.Locations.OfType <状态>()包含( 国家)第一()。; 
var countryForState = state.Country;

但是,这将需要在状态派生实体上称为国家的导航属性。我该怎么做?当我从数据库生成模型时,我有一个表,所有的FK指向同一个表中的记录:





(注意:我在DB中手动创建了这些FK)。 >

但是,FK被放置在位置实体的nav,所以我如何将这些导航属性移动到派生实体?我不能复制+粘贴导航,我不能创建新的导航属性,因为它不会让我定义开始/结束角色。



我们如何做?



如果我们可以先做模型,或者我们有一个DB来开始,那么TPH还不清楚,模型然后重新生成DB。我还没有在互联网上找到一个关于如何定义TPH的孩子的导航的例子。



注意:我不想做代码优先即可。我目前的解决方案具有TPT与EDMX和纯POCO,我希望不影响域模型/存储库(如果可能),只需更新EF模型/数据库。



编辑



仍然没有解决方案 - 但是我试图做模型先行,并进行Add - > New Association事实上,我可以向导出的实体添加导航。但是当我尝试从模型生成数据库时,仍然尝试为Location_Street,Location_Country等创建表。几乎像TPH不能首先被模型化。



编辑



以下是我当前的模型:





验证错误我目前正在获得: p>


错误1错误3002:从
开始映射
片段的问题359:潜在的运行时违反
表位置的键
(Locations.LocationId):列
(Locations.LocationId)映射到
EntitySet NeighbourhoodZipCode的
属性
(NeighbourhoodZipCode.Neighbourhood.LocationId)
在概念方面,但他们不
形成EntitySet的关键属性
(NeighbourhoodZipCode.Neighbourhood.LocationId,
NeighbourhoodZipCode.ZipCode.LocationId)。


只是想我会继续编辑这个问题与编辑关于我目前在哪里。我开始怀疑TPH是否具有自我参考FK的功能。



编辑



所以我想出了上面的错误,那是因为我几乎没有邻居ZipCode的连接表。



添加联接表(并将navs映射到那个)解决了上述错误。



但是现在我得到这个错误:


错误3032:映射
片段中的问题从行373开始,
382:条件成员
'Locations.StateLocationId'有
重复条件值。


如果我看看CSDL,这里是CountyState的关联映射(一个州有很多县,一个县有1个状态):

 < AssociationSetMapping Name =CountyStateTypeName =Locations.CountyStateStoreEntitySet =Locations> ; 
< EndProperty Name =State>
< ScalarProperty Name =LocationIdColumnName =StateLocationId/>
< / EndProperty>
< EndProperty Name =County>
< ScalarProperty Name =LocationIdColumnName =LocationId/>
< / EndProperty>
< Condition ColumnName =StateLocationIdIsNull =false/>
< / AssociationSetMapping>

这是 Condition ColumnName =StateLocationId这是抱怨,因为 ZipCodeState 关联也是这个条件。



但我不明白。所有实体的歧视者是唯一的(我已经三重检查了),我认为这是一个有效的方案:


  1. 县有一个单一状态,由StateLocationId(位置表)表示

  2. ZipCode有一个状态,由StateLocationId(位置表)表示

在TPH中无效?

解决方案

所以我解决了一些问题,但是首先,当您在数据库端创建自引用FK时,当您尝试从数据库更新模型时,实体框架将将这些导航属性添加到主基础类型,因为它没有明确的TPH意义 - 您需要在模型方面执行此操作。



但是,您可以手动添加



WRT这个错误:


错误3032:从第373行开始绘制片段的问题, 382:条件成员的Locations.StateLocationId'具有重复的条件值。


这是因为我有一个名为Location_State的FK尝试使用ZipCode_State关系和City_State关系 - 这不起作用(仍然不知道为什么)。



所以要解决这个问题,我不得不添加额外的列和额外的FK - 一个称为ZipCode_State,另一个称为City_State - 显然它必须是导航和物理FK之间的1-1。



< blockquote>

Location.LocationType没有默认值,不可空。需要一个列值来存储实体数据。


这是我的鉴别器字段。在数据库端,它是不可空



我阅读有关此问题的线程,他们表示您需要将关系从0 .. *到1 .. * - 但我的关系已经是1 .. *。



如果你看我上面的地点实际数据库表,所有的FK是空的(他们必须)。因此,我开始想知道我的关系是否应该是0 .. *。



但是由于TPH,它们是可以空的 - 并不是所有的位置都将有一个状态。但是,如果该地点是城市,那么它已经有一个州。



我的感受进一步被这个SO问题所安慰:ADO EF - TPH中派生类型之间的错误映射关联



我实际上正在尝试解决方法(在我甚至碰到它之前),解决方法对我来说不起作用。我甚至尝试将所有关系从1 .. *改为0 .. *,仍然没有运气。



在这里浪费太多时间,我已经回到TPT。



在一天结束的时候,TPH我会有一个可笑的大桌子,有很多很多冗余的可空列。加强智慧,更有效率。但是至少与TPT一样,我不需要具有可空的和自引用的FK。



如果有人解决了这个问题,让我知道。但直到那时,我坚持使用TPT。


I currently have a Entity Framework 4.0 model in place with Table Per Type (TPT), but there are a few performance issues (lots of LOJ's/CASE statements), as well as an issue mapping between two particular domain areas (many-to-many).

I've decided to try out TPH.

I have an entity called "Location" which is abstract, and the base for all other entities.

I then have "Country", "City", "State", "Street", etc which all derive from Location.

"LocationType" is the dicriminator.

That part is working fine, but i'm having issues trying to define navigational properties for the derived types.

For instance, a "State" has a single "Country", so i should be able to do this:

var state = _ctx.Locations.OfType<State>().Include("Country").First();
var countryForState = state.Country;

But this would require a navigational property called "Country" on the "State" derived entity. How do i do this? When i generate the model from the database, i have a single table with all the FK's pointing to records in the same table:

(NOTE: I created those FK's manually in the DB).

But the FK's are placed as nav's on the "Location" entity, so how do i move these navigational properties down to the derived entities? I can't copy+paste the navs across, and i can't "create new navigational property", because it won't let me define the start/end role.

How do we do this?

It's also not clear with TPH if we can do it model-first, or we HAVE to start with a DB, fix up the model then re-generate the DB. I am yet to find a good example on the internet about how to define navs on children with TPH.

NOTE: I do not want to do code-first. My current solution has TPT with the EDMX, and pure POCO's, i am hoping to not affect the domain model/repositories (if possible), and just update the EF Model/database.

EDIT

Still no solution - however im trying to do model-first, and doing Add -> New Association, which does in fact allow me to add a nav to the derived entities. But when i try and "Generate database from Model", it still tries to create tables for "Location_Street", "Location_Country" etc. It's almost like TPH cannot be done model first.

EDIT

Here is my current model:

The validation error i am currently getting:

Error 1 Error 3002: Problem in mapping fragments starting at line 359:Potential runtime violation of table Locations's keys (Locations.LocationId): Columns (Locations.LocationId) are mapped to EntitySet NeighbourhoodZipCode's properties (NeighbourhoodZipCode.Neighbourhood.LocationId) on the conceptual side but they do not form the EntitySet's key properties (NeighbourhoodZipCode.Neighbourhood.LocationId, NeighbourhoodZipCode.ZipCode.LocationId).

Just thought i'd keep editing this question with edit's regarding where i am currently at. I'm beginning to wonder if TPH with self-referencing FK's is even possible.

EDIT

So i figured out the above error, that was because i was missing the join-table for the Neighbourhood-ZipCode many to many.

Adding the join table (and mapping the navs to that) solved the above error.

But now im getting this error:

Error 3032: Problem in mapping fragments starting at lines 373, 382:Condition members 'Locations.StateLocationId' have duplicate condition values.

If i have a look at the CSDL, here is the association mapping for "CountyState" (a State has many counties, a County has 1 state):

<AssociationSetMapping Name="CountyState" TypeName="Locations.CountyState" StoreEntitySet="Locations">
   <EndProperty Name="State">
      <ScalarProperty Name="LocationId" ColumnName="StateLocationId" />
   </EndProperty>
   <EndProperty Name="County">
      <ScalarProperty Name="LocationId" ColumnName="LocationId" />
   </EndProperty>
   <Condition ColumnName="StateLocationId" IsNull="false" />
</AssociationSetMapping>

It's that Condition ColumnName="StateLocationId" which is complaining, because ZipCodeState association also this condition.

But i don't get it. The discriminators for all entities are unique (i have triple checked), and i would have thought this was a valid scenario:

  1. County has a single State, denoted by StateLocationId (Locations table)
  2. ZipCode has a single State, denoted by StateLocationId (Locations table)

Is that not valid in TPH?

解决方案

So i solved a few of my issues, but i hit a brick wall.

First of all, when you create self-referencing FK's in the database side, when you try and "Update Model from Database", Entity Framework will add these navigational properties to the main base type, as it has no explicit sense of TPH - you need to do this in the model side.

BUT, you can manually add the navigational properties to the child types.

WRT this error:

Error 3032: Problem in mapping fragments starting at lines 373, 382:Condition members 'Locations.StateLocationId' have duplicate condition values.

That was because i had an FK called "Location_State" which i was attempting to use for the "ZipCode_State" relationship, AND the "City_State" relationship - which does not work (still no idea why).

So to solve that, i had to add extra columns and extra FK's - one called "ZipCode_State", and another called "City_State" - obviously it has to be a 1-1 between navs and physical FK's.

Location.LocationType has no default value and is not nullable. A column value is required to store entity data.

That is my discriminator field. In the database side, it is not nullable.

I read threads about this issue, and they said you need to change the relationships from 0..* to 1..* - but my relationships already were 1..*.

If you look at my "Locations" actual database table above, all the FK's are nullable (they have to be). Therefore i started wondering if my relationships should be 0..*.

But they are nullable because of the TPH - not all "Locations" will have a "State". But if that Location is a "City", then it HAS to have a "State".

My feelings were further comforted by this SO question: ADO EF - Errors Mapping Associations between Derived Types in TPH

I was actually trying that workaround (before i even came across it), and the workaround does not work for me. I even tried changing all the relationships from 1..* to 0..*, and still no luck.

Wasting too much time here, I've gone back to TPT.

At the end of the day, with TPH i would have had a ridiculously large table, with lots and lots of redundant, nullable columns. JOIN-wise, it's more efficient. But at least with TPT i am not required to have nullable and self-referencing FK's.

If anyone has a solution to this problem, let me know. But until then, im sticking with TPT.

这篇关于实体框架4每层次表 - 如何定义儿童的导航属性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆