简体   繁体   中英

How to ignore part of a composite key in Entity Framework

I've been tasked with creating a windows service that transforms and migrates data from one database to another. The database that I am pulling from was developed by one of our sub-departments, and I have no say in the structure of that database.

My problem is that the database that I'm pulling from has some intrinsic flaws that I'm having trouble working around. The biggest one is that on many tables, the primary key is set up as a composite primary key... this wouldn't be that big of an issue, but the other tables that are supposed to be associated only have part of the composite key to reference.

For example, 'People' has ID and Surname as a composite key. ID is a surrogate auto increment integer key, and Surname is a varchar. The ID column alone is enough to uniquely identify a person, but for some reason they also included the surname in the composite key. 'Project' is supposed to reference 'People' to signify who the project is assigned to... but 'Project' just has 'PersonID', not the surname.

I was looking at their database and Access front end, and there is no actual relationship defined between the two.... it's just logically maintained via their front end.

So, how can I add my own navigation property if the table I'm joining from doesn't have all of the columns it needs as specified by the other table's composite primary key? Technically, I have the ID number, which is all I need to logically make the association, but entity framework requires that all of the composite key columns are mapped in the referential constraint.

I could ignore the navigation property and have my program add logic to get around the gaps, but lazy loading means that I would have to build my queries in stages then.

Is there some way to ignore a column of a composite key if it doesn't meaningfully contribute to the identity of the table?

EDIT

I should also note that I will never be writing to their database. I'm only going to be querying their data. The user account I'm connecting with has only been granted select permissions.

EF doesn't have to know about the composite keys. If you know for sure that a column is unique, you can fool EF and only tell it about the key field that matters. This requires some work though.

As you're working against an existing database I think the database-first approach will suit you best. Even then, there's a lot to do, but I think this is easier in an EDMX diagram then in manually typed code.

If you generate a model from your database the first thing you'll notice is that EF does not generate all associations in the EDMX. This is because EF only generates associations that involve the whole key (and nothing but the key) in the database.

Let me show this is in a highly simplified data model based on your example. After generating an EDMX model from this data model the diagram looks like this:

在此处输入图片说明

Person has a composite key and there's no association between Person and Project , although the FK is in the database. Now we're going to deceive EF in the following steps:

  • Remove Person.name from the primary key: right-click Name and uncheck "Entity Key".

  • Add an association between Person and Project : right-click Person , choose Add New, Association... Fill out the dialog as shown here:

    在此处输入图片说明

    Note that "Add foreign key properties..." is not checked. If it is, EF will add a new PersonId1 field.

  • Define the foreign key manually: right-click the association and choose "Properties".

  • In the Properties pane, click the ellipses at the right of "Referential Constraint".

  • Fill out the dialog:

    在此处输入图片说明

Now the diagram should look like this:

在此处输入图片说明

Done!

Or...? When you build the project or validate the diagram you will see an error appear:

Error 3003: Problem in mapping fragments starting at line 74:All the key properties (People.Id) of the EntitySet People must be mapped to all the key properties (Person.Id, Person.Name) of table Person.

EF isn't fooled that easily. We modified the conceptual model. Not the store model. EF still knows that Person has a composite key in the database. How can we fix that? Unfortunately (or fortunately?) there is no support for that in the EDMX designer. We have to edit the XML.

The first part of the XML contains the SSDL content , the store schema definition. Look for the store definition of Person , which should resemble this:

<EntityType Name="Person">
  <Key>
    <PropertyRef Name="Id" />
    <PropertyRef Name="Name" />
  </Key>
  <Property Name="Id" Type="int" StoreGeneratedPattern="Identity" Nullable="false" />
  <Property Name="Name" Type="nvarchar" MaxLength="50" Nullable="false" />
</EntityType>

Remove the line

    <PropertyRef Name="Name" />

Now the deception is complete, EF is happy, the model validates.

I must admit that I don't like this last part. It's a hack, whichever way you look at it. And when you update the model from the database all these carefully applied modifications in the store model are gone.

You won't have this problem if you work code-first. You could re-engineer the model from the database, using Entity Framework Power Tools or the new integrated "add new model" dialog in VS2013, and manually add all associations and remove all redundant keys. I think it's a lot more work, but at least it's "update-safe".

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM