I've got a conjunction table, which is a one to many relationship. My LINQ code will not insert into this table because it has no primary key, even though the table is composed of just foreign keys. In addition, when I try to save the relationship for one of my foreign keys, it says that the ALTER_TABLE statement conflicts with the FOREIGN_KEY constraint. But I've checked all through both of the tables in question and there is no ALTER_TABLE anywhere.
How can I make changes that will allow me to insert into my conjunction table?
Try creating a primary key on the table, that is a composite key of the foreign key columns. LINQ-to-SQL should like that a lot better. It will allow you to keep your current structure but provide a key that LINQ-to-SQL can use.
Related
I recently asked a question related to this and found a solution, but realized I may have a bigger problem. If anyone can tell me if I'm able to do what I describe below without making changes to the database it would be greatly appreciated! Note: I'm new to Entity Framework.
I am trying to insert into this table (Agreement Settings) duplicate SettingsId values for a new agreement (associated with an agreementId that is illustrated in the table as a column).
However, a SettingsId is also stored in a table with these columns Algorithm Settings. The Id column represents a SettingsId and is the primary key of this table.
I only want to update the Agreement Settings table (the former table above) with these new duplicate SettingsId values and leave the latter table alone. That way I will have agreements that have duplicate SettingsId guids but only one unique representation of that guid in the Algorithm Settings table.
When I try to insert into the database using Entity Framework:
dataTransferAgreement = (await _dataTransferContext.Agreements
.AddAsync(dataTransferAgreement))
.Entity;
I get brand new guids for SettingsIds returned, although the object dataTransferAgreement has the duplicate guids as properties beforehand (they are replaced). I assume this is because Entity Framework sees these foreign keys in Agreement Settings table and their association to Algorithm Settings table (the primary key) and automatically updates the primary key and thus the associated foreign keys on its own.
I of course can't add the Algorithm Settings table properties to dataTransferAgreement, as that would cause a primary key conflict.
The question: is there any way to manually (or otherwise) insert these duplicate foreign key values into Agreement Settings table without touching the Algorithm Settings table in Entity Framework (code first)? Currently, the entity property that inserts the primary key Id for SettingsId is decorated with [Key,DatabaseGenerated(DatabaseGeneratedOption.Identity)], which is used in numerous other places in this project, so I assume I cannot change that.
Also, the entity property that associates this table in the code:
[ForeignKey(nameof(SettingsId))]
public AlgorithmSetting AlgorithmSetting { get; set; }
is not needed in my case (since I don't want to do anything with it), but I can't just remove it due to it being a domain model (again, I'm an Entity Framework newbie so if I'm wrong in any way please correct me).
In your agreements settings table, add a primary key "id", alongside the other two columns you already have. Entity Framework and relational databases aren't going to support the same primary key.
If you need to query the agreement table in the future, you can do so with any column values and just "ignore" the new primary key you added.
Happy to help further if needed.
Tables in a many-to-many relationship are best handled by using a relationship (linking) table that only contains a Foreign Key to each table in the relationship. The relationship table itself should not have a Primary Key.
Start Edit (eesh 2017-06-18)
The above statement about the primary key is not true. A primary key should be used. The answer to the question is stated below. I have also changed the Title of this question to better reflect the problem.
Answer to Question: The linking table should have a primary key. The primary key should not be a unique generated Id column as is commonly used for other tables. Instead, it should contain a primary key that is a composite CK (candidate key) made up of the the two foreign keys that are the links for the Many-To-Many relationship. Please see the Stack Overflow question Creating composite primary key in SQL Server
Making this change causes the EF 6.0 to correctly generate the linking table as a table and not a view in the .edmx file. This change fixes the problem I was asking about and the question is answered. Thanks to Ivan Stoev and philipxy for pointing me in the right direction.
Everything below here is part of the original post which is resolved by simply creating a composite CK key for the linking table in SSMS as described above.
End Edit (eesh 2017-06-18)
When created in this fashion the relationship table does not appear in the .edmx diagram, but it is present in the edmx file. Configuring the tables in this fashion makes it easy to query the tables as each table in the relationship has a simple navigation property relating it to the other table.
Some examples of this can be found in the following links:
Entity Framework - querying a many-to-many relationship table
Entity Framework: Queries involving many to many relationship tables
Inserts and Updates should be straightforward as described in the following SO post:
Insert/Update Many to Many Entity Framework . How do I do it?
However, I found when I tried this I got the following error when trying to insert into a model that has a PackageManifest table, a Package table, and a PackageManifestAssignment table that links the two tables:
"Unable to update the EntitySet 'PackageManifestAssignment' because it has a DefiningQuery and no element exists in the element to support the current operation."
PackageManifestAssignment in the above is the linking table that links the PackageManifest table with the Package table. It only contains foreign keys for the PackageManifest and Package tables. There are no no other fields in the PackageManifestAssignment table.
Apparently this works fine when query existing relationships, but attempting to insert fails because EF 6.0 treats tables without Primary Keys as Views and, inserts are not allowed on views. Even though the association table isn't exposed to the programmer in the diagram view, it is present in the .edmx file and EF must insert a new entry in the association table for each new relationship created.
See links below for cause of error:
Entity Framework Error on SaveChanges()
It has a DefiningQuery but no InsertFunction element
Unable to update the EntitySet Table because it has a DefiningQuery and no InsertFunction element exists in the ModificationFunctionMapping element to support the current operation
In the above links an alternate solution is presented to creating a primary key for the table. Adding a primary key to the linking table would complicate CRUD for the tables in the relationship and creating relationship links. Hence, the preferred solution is to modify the .edmx file and make EF think that the table is not a view but is a table (which it is). This works. The instructions are:
Right click on the edmx file, select Open with, XML editor
Locate the entity in the edmx:StorageModels element
Remove the DefiningQuery entirely
Rename the store:Schema="dbo" to Schema="dbo" (otherwise, the code will generate an error saying the name is invalid)
Remove the store:Name property
In my particular case the change looked like:
Before Change:
<EntitySet Name="PackageManifestAssignment" EntityType="Self.PackageManifestAssignment" store:Type="Tables" store:Schema="dbo">
<DefiningQuery>SELECT
[PackageManifestAssignment].[PackageManifestId] AS [PackageManifestId],
[PackageManifestAssignment].[PackageId] AS [PackageId]
FROM [dbo].[PackageManifestAssignment] AS [PackageManifestAssignment]
</DefiningQuery>
</EntitySet>
After Change (Working Version):
<EntitySet Name="PackageManifestAssignment" EntityType="Self.PackageManifestAssignment" store:Type="Tables" Schema="dbo">
</EntitySet>
The drawback to manually making this change is that any time any table in the model is updated in the database and that change is carried over to EF using the .edmx "Update from Database/Refresh" option, the generated file (.edmx) file will overwrite the above changes to fix the error. Those changes will be required to be made manually again. This is both a cumbersome but more importantly fragile. If the change is not made future inserts for entries in the tables that use the linking table will fail. Developers making changes made many months or years down the line could easily forget this step.
Hence, the question is how to be able to keep the desired "easy to use" many-to-many relationship edit made to the .edmx file, without having to modify the .edmx file manually every time the model is updated from the database. Or, alternately is their another technique (marking the table in a certain way) or using a third party library to achieve this?
The relationship table itself should not have a Primary Key.
Every base table should have all CKs (candidate keys) declared, ie any column set(s) that have unique subrow values and that don't contain any smaller column set(s) that have unique subrow values. We can pick one as PK (primary key) and we declare any others as UNIQUE NOT NULL (which is the constraint that PK gives).
The entity id columns of an n-ary relationship/association table, aka linking/association/join table, form its PK, which, consisting of more than one column, is called composite. Per this answer:
HasKey(PackageManifestAssignment => new {
PackageManifestAssignment.PackageManifestId,
PackageManifestAssignment.PackageId
});
PS
Tables in a many-to-many relationship are best handled by using a relationship (linking) table that only contains a Foreign Key to each table in the relationship.
In general relationships/associations are n-ary. They can have attributes of their own. CKs/PKs can include entity or relationship/association (associative entity) CK/PK columns and attribute columns.
I need some functionality in my project and I don't know if its possible.
Here is a pic with the relations:
I need to update the keys relation table LessonByFacultyMember and the same keys in Scheduling table.
I mean the keys LessonNumber,LessonCoursenumber,FacultyMemberId (LessonByFacultyMember table)
and LessonNumber,CourseNumber,FacultyMemberId (Scheduling Table).
Is it possible to update this kind of relations?
UPDATE:
I just want to be clear that i mean the possibility to change the VALUE that stored in the keys dynamically in some method.
Yes you can do so by selecting Update Cascade option in Foreign key in the database.This options automatically updates the key values in the other tables. But in your case this is not needed. The table LessonByFacultyMember should have a column LessonByFacultyMemberId as a primary key and that should be in the Scheduling table as a Reference instead of putting all the three columns in the Scheduling table. If you do so ,you don't need to worry about the updating LessonNumber,CourseNumber,FacultyMemberId in the Scheduling Table. Also in your Scheduling table there should be a column SchedulingID as a Primary Key. You can take LessonByFacultyMemberId ,SchedulingID as an auto incremented integer. Also there is no need to make LessonNumber,CourseNumber,FacultyMemberId as a Primary key in the LessonByFacultyMember table. Instead you need to make them as unique key. Similarly in Scheduling table make the current primary key as unique key and have SchedulingId as primary key. In case of showing records you need to make select statement using joins and it is better to create a view for such statement. In case if still it is not clear , create a sqlFiddle on http://sqlfiddle.com/ for your schema and share that in your question or comment to this answer. I will update the same.
I have two tables:
CREATE TABLE Order (
orderId INTEGER IDENTITY NOT NULL,
PRIMARY KEY (orderId)
)
CREATE TABLE OrderAdditionalDetails (
additionalDetailsId INTEGER IDENTITY NOT NULL,
orderId INTEGER NOT NULL,
PRIMARY KEY (additionalDetailsId),
FOREIGN KEY (orderId) REFERENCES Order(orderId)
)
I have a Foreign key (FK_OrderAdditionalDetails_Order) declared on the OrderAdditionalDetails table, on the orderId field. I also have a 'unique' constraint on the orderId field in the OrderAdditionalDetails table. The idea is that each 'order' will have zero or one entries in the 'OrderAdditionalDetails' table.
This all picked up by the entity framework model file, however when I try to create the Navigation property, it only lets me declare a 1 to many relationship. The error I get is as follows:
Running transformation: Multiplicity is not valid in Role 'OrderAdditionalDetails' in relationship 'FK_OrderAdditionalDetails_Order'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be *.
I'm really not sure what this means - googling the error did not prove helpful. Can anybody shed some light on what I am doing wrong?
In your OrderAdditionalDetails table, remove the additionalDetailsID column and make the orderID the CLUSTERED PRIMARY KEY. Keep the FOREIGN KEY you already have. That is the right way to implement this.
There is not only no value added by the additionalDetailsId column, it makes things worse by taking more space in the table. The orderID is already a sufficient key; you need no secondary artificial key that is nothing but a surrogate for orderID.
Your Foreign Key must be defined as UNIQUE in order to enforce a One-To-Zero-Or-One relationship.
Maybe try something like this:
CREATE TABLE OrderAdditionalDetails (
additionalDetailsId INTEGER IDENTITY NOT NULL,
orderId INTEGER NOT NULL UNIQUE,
PRIMARY KEY (additionalDetailsId),
FOREIGN KEY (orderId) REFERENCES Order(orderId)
)
See Also: Implementing one-to-zero-or-one relation in SQL Server
I was trying to associate a table with a view of itself plus some other fields. (There is a very good reason for this that has nothing to do with the answer)
What cause the same error was there was more than one key field on the view. Even though I had specified the fields involved in the association it wanted both to be the only key fields for a 1 to 1 to work.
I also set the key field to be Distinct in the view, but I did that before I removed the key attribute of other fields, so it may ,or may not, be necessary.
Is there a way of editing the primary key in MVC3 if the table only contains a primary key field. For example I have a console table and within it i have the console name as the Primary key and I want to be able to edit it and change it and save the edited value.
If there is any more info you require please let me know.
As a general rule, you should never edit primary keys. The primary key in SQL Server typically has a clustered unique index on it, so editing the primary key means you potentially have to rebuild your indexes (maybe not every time, but depending on the skew).
Instead I would create a fake primary key, such as an IDENTITY column in SQL Server, and put a UNIQUE constraint on the Name column. If your table grows large, retrieving items on an int column will also be faster than retrieving on a varchar() column.
Update:
Since I was told I didn't answer the question (even though this is the accepted answer), it is possible to change the primary key values in SQL Server. But it is not technically an edit operation, since referential integrity may prevent a true edit (I haven't tried, so feel free to conduct your own experiment!)
The operation would go something like this:
Add a new row to the primary table, using the new PK value
Run an update operation to change all FK values to the new PK value
Delete the old PK row
I'd run all that in a transaction, too. But I will state again for the record, I do not recommend taking this approach.
As aKzenT pointed out, it is best to always use an Auto-Number/Identity or Sequence (Oracle) when defining primary keys. It is much more efficient for b-tree processors to find and join numeric keys, especially when textual ones are longer that a few bytes. Smaller keys also result in fewer b-tree pages that need to be searched.
Another important reason is that auto-generated keys cannot be modified. When using modifiable textual keys, foreign keys must employ CASCADE UPDATE which many (ex. Oracle, DB2) RDBMS do not support declaratively and must be defined using triggers, which is very complicated.
In your case, replacing the textual key with an auto-generated primary key will eliminate the problem.