Setting IsPrimaryKey=true on column in table with no primary key - c#

I'm writing a quick app using LINQ to SQL to populate a db with some test data and had a problem because one of the tables had no primary key as described by this bloke Can't Update because table has no primary key.
Taking the top answer I added the IsPrimaryKey attribute to an appropriate column and the app worked even though the I haven't changed the db table itself (i.e. there is still no primary key).
I expect it will be ok for my current intentions but are there any side effects which may come from having a table without a primary key seen as having one by the LINQ object?
(I can only think it might be a problem if I tried to read from a table (or populate to a table) with data where the 'primary key' column has the same value in more than one row).

When using an ORM framework, you can simulate keys and foreign keys at ORM level, thus "hiding and overriding" the database defined ones.
That said, that's a practice that I wouldn't recommend. Even if the model is more important than the database itself, the logical structure should always match. It is ok doing what you did if you're forced to work with a legacy database and you don't have the possibility to fix it (like adding the PK on the table). But try to walk the righteous path everytime you can :)
Tables without a PK = Pure Evil.

Basically if all the table updates go through the LINQ object you should be fine. If you have a DBA that decides to modify data directly though SQL then you can quickly run into issues if he duplicates a row with the same PK value.

Related

Updating relations in Linq To SQL is possible?

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.

LINQ to Entities returning incorrect results for tables without primary key

I have found that LINQ to Entities needs a primary key on the table in order to return correct results. Without it, I get the expected number of rows but including duplicates (and accordingly, missed rows). This problem is described here and here, and I consider it to be a bug.
In one of my tables, each row is unique but I cannot create a compound key across all fields because nullable columns cannot be used in primary keys (again, I consider this a SQL Server limitation).
So... how can I get correct results when selecting from this table using LINQ to Entities? I believe the "key" may be to create an "Entity Key" across all columns in the Visual Studio model designer but I'm not sure how to do this. Setting Entity Key = true on nullable columns throws an exception.
At one stage I gave up and added an identity int column with auto-increment enabled and used that as PK, which solved the issue, but I had to throw this out because of the volume of data being deleted/inserted all the time (it's not possible to simply reset the auto-increment counter on a schedule because not all of the rows are deleted, causing clashes).
My last resort will be to add a bigint identity column as PK, get rid of the auto-increment seed value resetter and hope it lasts "long enough" for the life of the application, but I'm not comfortable with this. (Edit: OK... it will last long enough. My main concern is performance)

Edit Primary Key

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.

Trying to do a hierarchical update results in an error "A foreign key value cannot be inserted"

I'm a bit of a noob with DAO and SQL Server and I'm running into a problem when I'm trying to insert values into two tables that have a relation. The table Photos has a gpsId field which has a foreign key relation with the id field of the GPSLocations table. I want to create a new Photos entry linked to a new GPSLocation, so the code looks something like this:
gpsRow = dataset.GPSLocations.AddGPSLocationsRow("0.0N", "3.2W");
dataset.Photos.AddPhotosRow(#"c:\path\file.jpg", gpsRow);
tableAdapterManager.UpdateAll(dataset);
However this results in the following error:
A foreign key value cannot be inserted
because a corresponding primary key
value does not exist. [ Foreign key
constraint name = photoToGps ]
I'm using SQL Server CE. Is my understanding correct that the TableAdapterManager should be handling this hierarchical update? I just dragged these tables onto the XSD view and relied on its automatic creation of the wrapper classes. Do I need to change anything about the relation (eg to make it a Foreign Key constraint)? I've noticed that under some circumstances the gps id is positive and sometimes negative, is that relevant?
EDIT:
I've also ensured that the update property is set to CASCADE, which results in the same error. Hierarchical updates are set to true and there is a foreign key constraint between the two tables in the designer.
It's just the configuration of your data set. Doubleclick the relation beween the tables in the Visual Studio's dataset designer, choose Both Relation And Foreigh Key Constraint option and in the Update Rule field choose Cascade option and that must be it.
Some information about the subject is in MSDN, you can look here http://msdn.microsoft.com/en-us/library/bb629317.aspx and go to the related topics.
I've managed to track down the source of this problem, which boils down to a limitation of SQL Server CE compared with the full SQL Server. It turns out the major hint that something wasn't right was because the ids were negative. The ids are negative in the DataSet before the row is inserted into the database, at which point it gets resolved to a positive index. The fact that it wasn't becoming a positive index happened because the TableAdapterManager normally does a batch statement of INSERT followed by a SELECT to update the id. However, SQL Server CE doesn't support batch statements, so this requires extra code to be written so that we simulate the SELECT step by responding to the RowUpdated event. This MSDN article explains the steps.
Did you enable Hierarchical Updates as described here?
Is there a foreign key constraint between the two tables (there should be a line on the XSD designer connecting them)? Since your fields are named differently it might not have been automatically added when you dragged the tables to the design surface.
Since the column photoToGps (foreign key) depends on the primary key (id), you cannot add a photoToGps unless there is a corresponding id present. So what you need to is individual updates, instead of doing an UpdateAll. First update the GPSLocations table, and then the other table. That way, you will have an id existing before you add a photoToGPS for it.

How to Update the primary key of table which is referenced as foreign key in another table?

Suppose a
Table "Person" having
"SSN",
"Name",
"Address"
and another
Table "Contacts" having
"Contact_ID",
"Contact_Type",
"SSN" (primary key of Person)
similarly
Table "Records" having
"Record_ID",
"Record_Type",
"SSN" (primary key of Person)
Now i want that when i change or update SSN in person table that accordingly changes in other 2 tables.
If anyone can help me with a trigger for that
Or how to pass foreign key constraints for tables
Just add ON UPDATE CASCADE to the foreign key constraint.
Preferably the primary key of a table should never change. If you expect the SSN to change you should use a different primary key and have the SSN as a normal data column in the person table. If it's already too late to make this change, you can add ON UPDATE CASCADE to the foreign key constraint.
If you have PKs that change, you need to look at the table design, use an surrogate PK, like an identity.
In your question you have a Person table, which could be a FK to many many tables. In that case a ON UPDATE CASCADE could have some serious problems. The database I'm working on has well over 300 references (FK) to our equivalent table, we track all the various work that a person does in each different table. If I insert a row into our Person table and then try to delete it back out again (it will not be used in any other tables, it is new) the delete will fail with a Msg 8621, Level 17, State 2, Line 1 The query processor ran out of stack space during query optimization. Please simplify the query. As a result I can't imagine an ON UPDATE CASCADE would work either when you get many FKs on your PK.
I would never make sensitive data like a SSN a PK. Health care companies used to do this and had a painful switch because of privacy. I hope you don't have a web app and have a GET or POST variable called SSN with the actual value in it!! Or display the SSN on every report, or will you shred all old printed reports and limit access to who views each report., etc.
Well, assuming the SSN is the primary key of the Person table, I would just (in a transaction of course):
create a brand new row with the new SSN, copying all other details from the old row.
update the columns in the other tables to point to the new row.
delete the old row.
Now this is actually a good example of why you shouldn't use real data as table cross-references, if that data can change. If you'd used an artificial column to tie them together (and only stored the SSN in one place), you wouldn't have the problem.
Cascade update and delete are very dangerous to use. If you have a million child records, you could end up with a serious locking problem. You should code the updates and deletes instead.
You should never use a PK with the potential to change if it can be avoided. Nor should you ever use SSN as a PK because it should never be stored unencrypted in your database. Never, unless your company likes to be sued when they are the cause of an indentity theft incident. This is not a design flaw to shrug off as this is legacy, we don't have time to fix. This is a design flaw that could bankrupt your company if someone steals your backup tapes or gets the ssns out of the sytem in another manner (most of these types of thefts are internal BTW). This is an urgent - must fix now design flaw.
SSN is also a bad candidate because it changes (people change them when they are victims of identity theft for instance.) Plus an integer PK will have faster performance than a nine-digit PK.

Categories

Resources