I have Table
eventid int -- not PK key but with autoincrement
jobid -- PK autoincrement disabled
userid int -- PK autoincrement disabled
To update jobID I do following:
var itemforupdate = context.table.where(n=>n.eventid == someparameter).FirstorDefault()
I get the item from database correctly, but when assigning:
itemforupdate.jobID = 5;
context.SaveChanges();
after context.SaveChanges() I get the error:
The property 'jobID' is part of the object's key information and
cannot be modified
How to update jobID from Entity Framework to solve this problem?
Updating primary key columns is not a good practice with EntityFramework. It confuses EF because it changes the identity of the object, and makes keeping the in-memory copy and the in-database copy of the data in sync very problematic. So it's not allowed.
Just don't update primary keys. Instead delete one row and insert a new one.
Alternatively you can update the primary key directly with a stored procedure or other query.
Related
This is doing my head in. I have a pretty simple model class like this (generated by EF Core Power Tools):
In the Azure SQL database, I have the following foreign key relationship in place which associates a Sighting record with to every MachineLearningTaggedImage record:
ALTER TABLE [dbo].[MachineLearningTaggedImage] WITH CHECK
ADD CONSTRAINT [FK_MachineLearningTaggedImage_Sighting]
FOREIGN KEY([SightingId]) REFERENCES [dbo].[Sighting] ([SightingId])
GO
ALTER TABLE [dbo].[MachineLearningTaggedImage]
CHECK CONSTRAINT [FK_MachineLearningTaggedImage_Sighting]
GO
I am then trying to do a very run of the mill insert, with the SightingId value populated (because I want the newly inserted MachineLearningTaggedImage record to link to an existing Sighting record that already exists in the database):
var newImageTag = new MachineLearningTaggedImage
{
SightingId = sighting.SightingId
};
_db.MachineLearningTaggedImages.Add(newImageTag);
Save();
But the insert fails with the following error:
The MERGE statement conflicted with the FOREIGN KEY constraint "FK_MachineLearningTaggedImage_Sighting". The conflict occurred in database "MyDatabase", table "dbo.Sighting", column 'SightingId'.
I'm puzzled because my existing value of SightingId (3398670) definitely exists in the Sighting table as an existing record which I want to link to.
But for some reason, EF Core or SQL won't let me do this insert.
Now if I go directly into a SQL query window (outside of EF Core), I can successfully insert the new MachineLearningTaggedImage record with a SightingId value = 3398670 - no problem at all. It works..
What am I running into? Is it something related to me having only populated the SightingId value, but the actual Sighting child / related object property is still null when I attempt to insert? I thought you could simply populated an ID of a related object and EF Core would be happy with that.
I have a ward table and it contains columns like wardid, wmemname, isActive, and so on... wardid is the primary key and isActive is boolean.
If the user deletes the record from the front end, I set isActive to false.
"Record is deleted successfully"
This message is shown to the user.
In my delete procedure I wrote an update statement to make isActive set to false:
update wardtable
set isActive = false
where wardid = #wardid
Fine up to here. In case the user wants to enter the details with the deleted wardid, now there is a problem with a primary key violation message from the front end when he tries to enter the data with the deleted wardid.
How to solve this issue?
Suppose if I take another id in my ward table then, it allows if I make id as an autoincrement. But duplicate wardid's are allowed in my ward table if I do like that.
So, what is the best way to do this?
Your doing too much with your primary key.
Create a real primary key of type uniqueidentifier / long and auto generated if need be.
Wardid should NOT be your primary key for this table, use your business logic to lookup data on this column and update / delete / insert as required. leave the new primary key for use by your database only. If wardid needs to be unique, make it a unique column by adding it to a unique index or use business logic.
To add on to uk2k05's answer an example of how you would implment it would be
CREATE TABLE dbo.wardtable
(
wardTableId bigint NOT NULL IDENTITY (1, 1),
wardid int NOT NULL,
deletedUniqueifier uniqueidentifier NOT NULL default('00000000-0000-0000-0000-000000000000'),
wmemname varchar(50) NOT NULL,
isActive AS (case when deletedUniqueifier = '00000000-0000-0000-0000-000000000000' then 1 else 0 end) PERSISTED
)
ALTER TABLE dbo.wardtable ADD CONSTRAINT
PK_wardtable PRIMARY KEY CLUSTERED (wardTableId)
CREATE UNIQUE NONCLUSTERED INDEX UX_wardtable_wardid
ON dbo.wardtable (wardid, deletedUniqueifier)
Now that isActive is a computed column your update would also have to change to
update wardtable
set deletedUniqueifier = newid()
where wardid = #wardid and deletedUniqueifier = '00000000-0000-0000-0000-000000000000'
One other logical change you will need to do, any forgen keys that link to this table should link using wardTableId instead of wardid
I have the following table:
create table tbl
(
id int identity(1,1),
val varchar(100)
)
Now when i use Entity Framework to map objects to this table, it works, however when i change the table definition as follows:
create table tbl1
(
id int,
val varchar(100)
)
Entity Framework does not maps objects to this table. Any clue as to why is this happening would be appreciated.
Entity Framework requires a Primary Key to generate a model from the database. If there is no Primary Key on a table it will simply select the non-nullable columns as a concatenated primary key and the Entity will be read/only.
In your first table identity definition makes your id column non-nullable so you were able to create an Entity. You should have seen this message while adding that table:
"The table/view 'tbl1' does not have a primary key defined. The key
has been inferred and the definition was created as a read-only
table/view."
In your second table however there is no non-nullable column and EF cannot create an Entity for it. See the message when you try to add it:
"The table/view 'tbl1' does not have a primary key defined and no
valid primary key could be inferred. This table/view has been
excluded. To use the entity, you will need to review your schema, add
the correct keys, and uncomment it."
Entity frameworks generally need a way to distinguish between two records in a table and so require a ID/Key discriminator which need not be a primary key constraint or a unique key constraint or an identity at the DB layer. But this discriminator, a column or a set of columns, should help the entity framework identify a record uniquely and distinguish it from other records. So, you need to define such a discriminator in your entity class at the C# layer.
Have a problem with incrementing.
I created a new object and tried set it into my DB I received an error of data violation. The index in table wasn't increased (Id=0).
Id - set as primary key in SQL table and the StoredGeneratedPattern property of field "Id" in EDM set as "Identity" so, obviously, it must be incremented automatically.
public void AddPhone(UserPhone phone)
{
context.AddToUserPhone(phone);
context.SaveChanges();
}
I can't understand why.
Entity Framework does not automatically increment IDs. That's the database's job. Set the ID column on the database table as an IDENTITY column so that it will auto-increment. Then you should find that after you SaveChanges() the phone's ID property will have been set to the value the database chose for it.
I have another question kind of relative to this but I'd like to separate them for clarity reasons.
I stumbled upon a problem where I couldn't insert a new row in a table because it only had one column and that column was incrementally increased and PK.
However, creating a new object of that Set in Entity Framework was no trouble at all.
var admin = new Administrator {};
context.Administrator.AddObject(admin);
context.SaveChanges();
int adminId = admin.adminId; //This would give me the new value
How does this work?
When you commit your changes, Entity Framework performs an INSERT into the table associated with the Administrator entity set, for each added entities.
As the PK is auto incremented in the database, EF knows that it doesn't need to provide it, but retreive it after the INSERT. It then updates the Administrator entity with it's now available (and database generated) PK.
It's classic Object relational Mapping job, I hope I understood your question?
Here is the exact SQL query sent by EF to do the Insert job.
insert [dbo].[Entities] default values
select [Id]
from [dbo].[Entities]
where ##ROWCOUNT > 0 and [Id] = scope_identity()
It inserts a default row in the table, then select the new row's Id.