I've got two keys, and want to update the foreign keys in a single query, without pulling it out first(for efficiency reasons)
In other words, I'm wondering if there's any way to run the following query with entity
UPDATE User_Conversation
SET LastReadMessageId = #lastReadMessageId
WHERE Id = #userConversationId
AND UserId = #currentUserId -- for security
You can use "Attach" function with State=Modified for fields that you want to update.
Check here for more information.
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.
Using Entity Framework 6.x. For some entities after I create a new instance of an entity object and populate it with data values, I would then like to be able to trigger a lookup on the database. I would like to see if a row exists with all the same values that where populated into the entity object and if it exists return the primary key.
It seems logical that there should be a standard way to do this built into the entity framework but I can't find it. It would be nice if there was a method that would just take any entity object and return the primary keys of any matching rows.
What's wrong with just doing a FirstOrDefault() filter to retrieve an entity with matching values?
var entity = new Entity { // initialize some properties }
var matched = dbContext.EntityTable.FirstOrDefault(x => x.PropA = entity.PropA && x.PropB = entity.PropB);
(Don't have EF on my machine right now, the actual access code is just psuedo)
This is not possible. You have to create query with all data values that you want to check. Another option is to have checksum column that contains some hash from all values (without the primary key), then you can compute the hash from newly created entity and query database if entity with such hash exist.
Edit: Additionaly there is an option to create multi column Constraint in SQL Server (check this: Unique constraint on multiple columns), but it doesn't return primary key of duplicated row in a convenient way.
I have a table in my database.
This table has one column named A, the column is not entity or auto number, unique key or...
I created a model from my db with Entity Framework 4.1.
My code
using (var contex = new testEntities())
{
Table_1 t = new Table_1();
t.A = 1;
contex.Table_1.Add(t);
contex.SaveChanges();
}
I do not want to use the identity number or index in my table.
When I want to insert a row in it it gives me this error:
Unable to update the EntitySet 'Table_1' because it has a DefiningQuery and no
<InsertFunction> element exists in the <ModificationFunctionMapping> element to
support the current operation.
You either have to give the table a primary key (which you don't seem to want to do) or you need to provide a function to tell Entity Framework how data can be inserted into the database.
I would strongly suggest that you put a primary key on your table unless you have a very good reason for not doing this, and in all my years I can't think of many instances when I wanted a table without a primary key.
If you don't want the primary key at all, then you might find this article useful about using Stored Procs for INSERTing data into the database: http://msdn.microsoft.com/en-us/data/gg699321.aspx
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?
so I have an old database that I'm migrating to a new one. The new one has a slightly different but mostly-compatible schema. Additionally, I want to renumber all tables from zero.
Currently I have been using a tool I wrote that manually retrieves the old record, inserts it into the new database, and updates a v2 ID field in the old database to show its corresponding ID location in the new database.
for example, I'm selecting from MV5.Posts and inserting into MV6.Posts. Upon the insert, I retrieve the ID of the new row in MV6.Posts and update it in the old MV5.Posts.MV6ID field.
Is there a way to do this UPDATE via INSERT INTO SELECT FROM so I don't have to process every record manually? I'm using SQL Server 2005, dev edition.
The key with migration is to do several things:
First, do not do anything without a current backup.
Second, if the keys will be changing, you need to store both the old and new in the new structure at least temporarily (Permanently if the key field is exposed to the users because they may be searching by it to get old records).
Next you need to have a thorough understanding of the relationships to child tables. If you change the key field all related tables must change as well. This is where having both old and new key stored comes in handy. If you forget to change any of them, the data will no longer be correct and will be useless. So this is a critical step.
Pick out some test cases of particularly complex data making sure to include one or more test cases for each related table. Store the existing values in work tables.
To start the migration you insert into the new table using a select from the old table. Depending on the amount of records, you may want to loop through batches (not one record at a time) to improve performance. If the new key is an identity, you simply put the value of the old key in its field and let the database create the new keys.
Then do the same with the related tables. Then use the old key value in the table to update the foreign key fields with something like:
Update t2
set fkfield = newkey
from table2 t2
join table1 t1 on t1.oldkey = t2.fkfield
Test your migration by running the test cases and comparing the data with what you stored from before the migration. It is utterly critical to thoroughly test migration data or you can't be sure the data is consistent with the old structure. Migration is a very complex action; it pays to take your time and do it very methodically and thoroughly.
Probably the simplest way would be to add a column on MV6.Posts for oldId, then insert all the records from the old table into the new table. Last, update the old table matching on oldId in the new table with something like:
UPDATE mv5.posts
SET newid = n.id
FROM mv5.posts o, mv6.posts n
WHERE o.id = n.oldid
You could clean up and drop the oldId column afterwards if you wanted to.
The best you can do that I know is with the output clause. Assuming you have SQL 2005 or 2008.
USE AdventureWorks;
GO
DECLARE #MyTableVar table( ScrapReasonID smallint,
Name varchar(50),
ModifiedDate datetime);
INSERT Production.ScrapReason
OUTPUT INSERTED.ScrapReasonID, INSERTED.Name, INSERTED.ModifiedDate
INTO #MyTableVar
VALUES (N'Operator error', GETDATE());
It still would require a second pass to update the original table; however, it might help make your logic simpler. Do you need to update the source table? You could just store the new id's in a third cross reference table.
Heh. I remember doing this in a migration.
Putting the old_id in the new table makes both the update easier -- you can just do an insert into newtable select ... from oldtable, -- and the subsequent "stitching" of records easier. In the "stitch" you'll either update child tables' foreign keys in the insert, by doing a subselect on the new parent (insert into newchild select ... (select id from new_parent where old_id = oldchild.fk) as fk, ... from oldchild) or you'll insert children and do a separate update to fix the foreign keys.
Doing it in one insert is faster; doing it in a separate step meas that your inserts aren't order dependent, and can be re-done if necessary.
After the migration, you can either drop the old_id columns, or, if you have a case where the legacy system exposed the ids and so users used the keys as data, you can keep them to allow use lookup based on the old_id.
Indeed, if you have the foreign keys correctly defined, you can use systables/information-schema to generate your insert statements.
Is there a way to do this UPDATE via INSERT INTO SELECT FROM so I don't have to process every record manually?
Since you wouldn't want to do it manually, but automatically, create a trigger on MV6.Posts so that UPDATE occurs on MV5.Posts automatically when you insert into MV6.Posts.
And your trigger might look something like,
create trigger trg_MV6Posts
on MV6.Posts
after insert
as
begin
set identity_insert MV5.Posts on
update MV5.Posts
set ID = I.ID
from inserted I
set identity_insert MV5.Posts off
end
AFAIK, you cannot update two different tables with a single sql statement
You can however use triggers to achieve what you want to do.
Make a column in MV6.Post.OldMV5Id
make a
insert into MV6.Post
select .. from MV5.Post
then make an update of MV5.Post.MV6ID