I'm adding objects to a database where the id isn't auto-autogenerated in the database due to me wanting to specify the id myself (It's stupid I know, just play along ^^)
So I'm using Entity Framework 5 to insert the data into the database, however, eventhou I set the id before saving it, when I look in the database it's always zero. Why is this and how do I fix it?
The code is like this:
public Profile Add()
{
Profile item = new Profile()
{
id = 1,
name = "Bob"
};
db.Entry(item).State = EntityState.Added;
db.SaveChanges();
return item;
}
EDIT
I tried with db.Profiles.Add(item). Same problem
1.- In your edmx designer, right click id column, select properties
2.- In StoreGeneratedPattern select None
As PhilipStuyck said, your model was out of sync with your database, whenever you change the database you must update the model (Right click empty space in edmx designer select Update model from database).
Check that your database and your model are actually the same.
If you created your model from an existing database and then changed the database then your model is out of sync. This can also happen with code first of course.
Bottom line is that your sql will do an insert without a value for id, because EF thinks your id is going to come from the database. If you inspect the sql you will see an insert without id being provided followed with a select to get the value for id.
Conclusion is that your model and db are not the same.
Right click the designer and do update model from database.
You might have to remove your id column, or the table to begin with, EF will correct everything
You need to specify the table that you are adding it to.
so for you that would be db.NAMEOFTABLE.add(item)
normally you don't have to change the entity state to added.
Atleast I didn't have to do that in my solution.
You need to add the entity to the DbSet that represents your profiles table... something like this...
public Profile Add()
{
Profile item = db.Profiles.Create();
item.Name = "Bob";
db.Profiles.Add(item);
db.SaveChanges();
return item;
}
I prefer using the Create method however it makes no difference.
By default Id property is treated as Primary Key and as Identity by Entity Framework. So it just ignores property value, while generating sql for insert command. You should specify metadata explicitly: add [DatabaseGenerated(DatabaseGeneratedOption.None)] attribute or use method HasDatabaseGeneratedOption from FluentApi.
Related
We have an entity for which we want to save old versions as revisions, what is the best way to achieve this?
The current idea is to have two properties Id and Revision that combined makes up the primary key. I am not sure if this is the correct approach, and I have issues with how to get the database to generate the values - if I do not set them myself.
If I save a completely new entity I want both Id and Revision to be set. ´Id´ to the next id in order, and Revision to zero.
If I save a new version of an entity I would set the Id to the id of the entity I want to create a new revision of (together with all other values I might want to bring over to the new entity). I would like to leave the ´Revision´ property empty, and the database should then increment this and set it to the previous latest revision value + 1.
How can I achieve this functionality with entity framework? Can I achieve it with entity framework?
Edit
I have tried this setup in my DbContext implementation:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<EntityDao>().HasKey(m => new { m.Id, m.Revision });
modelBuilder.Entity<EntityDao>().Property(m => m.Id).ValueGeneratedOnAdd();
modelBuilder.Entity<EntityDao>().Property(m => m.Revision).ValueGeneratedOnAdd();
}
But then I get this error:
Only one column per table can be configured as 'Identity'.
If I remove the ValueGeneratedOnAdd statement on the Revision property, the service is able to start. But then I get an error on save since Revision is null - unless I manually give it a value.
There was also an issue that I could not explicitly set the Id property when I had the ValueGeneratedOnAdd statement. I got the following error:
Cannot insert explicit value for identity column in table 'Entities' when IDENTITY_INSERT is set to OFF.
But I found this info on how to solve that:
explicit-values-generated-properties
As for me the better option would be to create another versions table where you can store all of the entity versions with the entity id foreign key. And when you create completely new entity you just put it in the main table, but when you modify entity you just store existing entity inside versions table with foreign key, and update your entity in the main table. With that approach you would have the main table with only last versions of entities, so you don't need to filter them on get. And versions table from where you always can get all the versions with timestamp and some additional info that you want to have.
I've got an issue with SQLite and EntityFramework.
My entity class has an Id property which maps to an identity column that is also the PK. When I insert a new entity model object to my DB via
_dbContext.Images.Add(imageEntity);
_dbContext.SaveChanges();
then it will always insert the object with imageEntity.Id = 0 because 0 is default for int. There is an attribute [NotMapped] which isn't what I need, it's for when you have an additional property in your entity class that doesn't exist in the table. Mine exists in the table, I just don't want to write it, the DB should take care of this.
I would like to make EF behind the scenes to produce a statement like this:
insert into Images (Views, Rating) values (100, 5.5)
instead of this:
insert into Images (Id, Views, Rating) values (0, 100, 5.5)
Anybody an idea how to do this?
Also the latter insert statement works (if there's no Id = 0 entry already), but why? Shouldn't an identity column always be protected from outside value insertion?
UPDATE:
As a workaround I've tried to let EF create a new entity model for me like this
var temp = _dbContext.Images.Create();
I thought maybe then I'll be able to replace everything except for the Id value and save it to the DB, but what I get is an object with temp.Id = 0 again. I don't know if EF or SQLite is fooling me
You can try:
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
As attribute of your property.
This leaves responsibility of generating values on insert to db
I'm trying to design a rollback changes system.
I'm tracking old record values when a record id modified or deleted and then I'm using that values to re-insert it when user choose to rollback it...
editions rollback are working as expected.
deletions are not... because when I attach the entity to DBContext it has the old Id but when I execute DbContext.SaveChanges(); the Id is replaced per a new one(Auto Incremented)
Here is the sample code:
var model = JsonConvert.DeserializeObject(oldValues.OldData, type);
DbSet mySet = this.Set(type);
mySet.Attach(model);
this.Entry(model).State = oldValues.AuditType == 0 ? EntityState.Modified : EntityState.Added;
base.SaveChanges();
into model.Id I can see the correct Id before save but after it EF changes it per a new one.
is there anyway to set temporally to keep the current Id instead of generate a new one?
I tried many solutions but none of them works.
Thanks
To disable the Auto Generated Id, you have to run this command in SQL:
SET IDENTITY_INSERT [<schema>].[<TableName>] ON;
Then you can insert whatever value you want for the PK, assuming it is still available. However, I don't think EF has a way to do this from code.
I'm not entirely sure this would work, but, in theory, you could run some ad-hoc SQL right before save-changes on a transaction you create and then see if EF will take it.
If that doesn't work, then try this:
ALTER TABLE theTableInQuestion AUTO_INCREMENT=1234
EIDT: Or try this approach:
How can I force entity framework to insert identity columns?
i make table for property name that changed and value before and value after
How i can use Change Tracking to store changed in this table?
You can track the operation, the changed columns and the new values by using Change Tracking. However getting the old Value out of Change Tracking is not possible. SQL Server 2016 offers the new feature "Change data capture", which gives you the needed Information about the old value before the update/delete happened ( see https://msdn.microsoft.com/en-us/library/bb933994.aspx ).
If you don't have access to a SQL Server 2016, here is how you can configure Change Tracking:
Activate at Database
ALTER DATABASE <YourDatabase> f.e. DeviceDatabase
SET CHANGE_TRACKING = ON
(CHANGE_RETENTION = 2 DAYS, AUTO_CLEANUP = ON)
Activate Change Tracking for your needed tables
ALTER TABLE <YourTable> f.e. Devices
ENABLE CHANGE_TRACKING
WITH (TRACK_COLUMNS_UPDATED = ON)
Setup a DB Job, which will copy change-information into your custom table every minute,hour,day (what you need)
DECLARE #minversion bigint;
SET #minversion = (SELECT MinVersion = CHANGE_TRACKING_MIN_VALID_VERSION(OBJECT_ID('Devices')) )
SELECT SYS_CHANGE_COLUMNS, e.Id FROM
CHANGETABLE(CHANGES Devices, #minversion) AS C
LEFT OUTER JOIN Devices AS e
ON e.Id = c.Id;
To Get the latest Value of the Changed Column you can try this (but beware of multiple updates of the same row. you only get the latest value).
CHANGE_TRACKING_IS_COLUMN_IN_MASK
(COLUMNPROPERTY(OBJECT_ID('Devices'), 'Id', 'ColumnId')
,c.sys_change_columns)
This will return 1 if Column changed, 0 if not. You can add this for every column of your table and join on value = 1 and then add the value to your query.
Finally, I would just recommend to use Stored Procedures to Update/Insert/Delete on your Tables. In those you can easily insert all information you want to store about the change in your custom table.
If you have SQL Server 2016 tho, try what I mentioned above, eventually.
Actually if you override the SaveChanges() method in your data context class you can access ChangeTracker. This gives you all the entities currently tracked by the context and their EntityState (if they are added/modified/deleted/unchanged etc).
Here you can get the DbEntityEntry class and from that get the entitys current values and/or its previous values if the entity is in the modified state.
public override int SaveChanges()
{
var allTrackedEntities = this.ChangeTracker.Entries().ToList();
return base.SaveChanges();
}
I currently use this method to do some basic auditing of who is doing that to what entity.
Entity Framework 4 Returning KEY/Primary Key
I’m Trying to find a way to Return a Key/Primary Key without having to create a stored procedure to do it for me using:
CREATE PROCEDURE [dbo].[UserRecords]
(
#Name varchar(10)
) AS
-- INSERT the new record
INSERT INTO MyTable (Name)
VALUES(#Name)
-- Now return the InventoryID of the newly inserted record
SELECT SCOPE_IDENTITY() AS ID
Though Visual Studio 2010 I then Use the Add Function Import From the Model Browser and Create a Complex Type.
Then Though C# i use the Following Code to check its working.
SQL_DB_Entities DB= new SQL_DB_Entities();
var ReturnValue = DB.UserRecords("BOB").First();
Console.Write(ReturnValue.ID);
Console.Read();
I'm simply looking for a better way to return the ID and also being very sure im not going to cause head aches for myself laster on down the track.
If you feel this is not the best way to return the key please let me know.
I have Tried it this way but returns 0
SQL_DB_Entities DB = new SQL_DB_Entities();
User UserObject = new User{Name = “BOB”};
DB.AddToUserTable(UserObject);
DB.SaveChanges():
Int key = UserObject.ID;
Console.WriteLine(key.ToString());
I should also mention that the DB is looking after the Primary Keys not my application.
If you correctly setup StoreGeneratedPattern to Identity in your entity and if you have autogenerated PKs in the database, EF will fill the Ids of your inserted entities after each save changes. Check this article to understand store generated pattern.
Normally PKs are dealt with as a particular property on an EF Object EntityKey. You are probably best to have a look at EntityKeys.
The usual way is to set the StoreGeneratedPattern property of the PK column in your model as Identity. Or if you are using code-first, annotate the property with:
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
I am not sure whether this works with sprocs, though. By the way, any special reason you are using sprocs in this case?