I am currently trying to migrate from an old MySQL (5.0) to MSSQL. Because I must keep the primary key relationships, I am now facing a problem. Some data inside a table begin with the id of 6102 instead of one. I can solve this by increasing the seed, which works. Now, after several thousand of data sets, I have some leaps e.g. from id 22569 to 22597. This occurres multiple times.
What I basically do at the moment is, select all data from the source db (MySQL), map them into a generated model und try to map this model to my target model (MSSQL). (I do this because the target, new structure differs a little from the existing one.) When I ignore those leaps, I am getting later on several other tables a foreign key violation.
So my solution currently would be, to count from the beginning each mapping and when the id of the current model differs from the counter, to reset manually the seed in the database.
DBCC CHECKIDENT (mytable, RESEED, idFromCurrentModel);
Is there a possibility to force entity framework, respectively SQL Server to accept the id from my model instead of ignoring it and use the ident value?
Thanks for reading and best regards
EDIT
Just if anybody is wondering how I solved this, here it is:
var context = new TestEntities();
// map mysql data to mssql model and convert data
// let's assume I did this
var mapped = new List<Test>()
{
new Test() {id= 42, bar = "foo", created = DateTime.Now},
new Test() {id= 1337, bar = "bar", created = DateTime.Now}
};
var transaction = context.Database.BeginTransaction();
context.Database.ExecuteSqlCommand("SET IDENTITY_INSERT [SeedingTest].[dbo].[Test] ON");
context.Test.AddRange(mapped);
context.SaveChanges();
context.Database.ExecuteSqlCommand("SET IDENTITY_INSERT [SeedingTest].[dbo].[Test] OFF");
transaction.Commit();
context.Dispose();
This only works when I do this:
Right click on my *.edmx file, open, and remove the
StoreGeneratedPattern="Identity"
in your identity column. In my case this looked like this:
...
<Property Name="id" Type="int" Nullable="false" StoreGeneratedPattern="Identity" />
...
After removing this, EF was no longer ignoring my set id's.
Source
Additional information:
Adding this attribute
[DatabaseGenerated(DatabaseGeneratedOption.None)]
to my id in my generated model, did not work.
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int foo { get; set; }
public string bar { get; set; }
...
The easiest way is to set the seed initially to the current max Id value + 1. Then, when inserting the converted rows do the following
set identity_insert on tablename -- stops generation of IDENTITY, requires user to supply it
insert into tablename values (Id....) -- supply value of Id
set identity_insert_off tablename -- turn inedtity generation back on
This does it quite nicely.
Related
I'm using entity framework 4.1 (VS 2010, SQL Server 2012) for inserting data into a database.
First I create an instance of an object, fill the properties with values and call AddObject(), like this:
VideoData videodata = new VideoData();
videodata.StartCaptureTime = startCaptureTime;
videodata.EndCaptureTime = endCaptureTime;
videodata.CameraID = CameraID;
using (var context = new PercEntities())
{
if (context.VideoDatas.Where(c => c.VideoID == videoID).Count() == 0)
{
var videoData = new VideoData
{
StartCaptureTime = startCaptureTime,
EndCaptureTime = endCaptureTime,
CameraID = CameraID,
};
context.VideoDatas.AddObject(videoData);
context.SaveChanges();
}
}
The thing is, that the table in the database has an identity column:
VideoID int IDENTITY(1,1)
and I need to get the value inserted by the identity function in order to fill additional objects, that have the VideoID as a foreign key. for example:
FrameData frameData = new FrameData();
frameData.VideoID = videodata.VideoID;
frameData.Path = path;
The only thing I could think of was to query for the max identity right after AddObject(videoData), but I'm afraid of race conditions.
I'm new to Entity Framework, so I'd be happy for any guidance on this.
If you have other objects which require VideoID as FK you just need to correctly configure your navigation properties between VideoData and those other types and EF will handle it for you.
Call to AddObject does not insert your data to database and because of that you cannot get the identity value after this call. Only call to SaveChanges will push all your changes to database and during this call EF will handle referential integrity internally (but only if you have your model correctly configured with relations).
After calling SaveChanges your VideoID should be populated automatically if you have everything correctly configured.
I'm using Hibernate to access MySQL, and I have a table with an auto-increment primary key.
Everytime I insert a row into the table I don't need to specify the primary key. But after I insert a new row, how can I get the relative primary key immediately using hibernate?
Or I can just use jdbc to do this?
When you save the hibernate entity, the id property will be populated for you. So if you have
MyThing thing = new MyThing();
...
// save the transient instance.
dao.save(thing);
// after the session flushes, thing.getId() should return the id.
I actually almost always do an assertNotNull on the id of a persisted entity in my tests to make sure the save worked.
Once you're persisted the object, you should be able to call getId() or whatever your #ID column is, so you could return that from your method. You could also invalidate the Hibernate first level cache and fetch it again.
However, for portability, you might want to look at using Hibernate with sequence style ID generation. This will ease the transition away from MySQL if you ever need to. Certainly, if you use this style of generator, you'll be able to get the ID immediately, because Hibernate needs to resolve the column value before it persists the object:
#Id
#GeneratedValue (generator="MY_SEQ")
#GenericGenerator( name = "MY_SEQ",
strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",
parameters = {
#Parameter(name = "sequence_name", value = "MY_SEQ"),
#Parameter(name = "initial_value", value = "1"),
#Parameter(name = "increment_size", value = "10") }
)
#Column ( name = "id", nullable = false )
public Long getId () {
return this.id;
}
It's a bit more complex, but it's the kind of thing you can cut and paste, apart from changing the SEQUENCE name.
When you are calling a save() method in Hibernate, the object doesn't get written to the database immediately. It occurs either when you try to read from the database (from the same table?) or explicitly call flush(). Until the corresponding record is not inserted into the database table, MySQL would not allocate an id for it.
So, the id is available, but not before Hibernate actually inserts the record into the MySQL table.
If you want, you can get the next primary key independently of an object using:
Session session = SessionFactoryUtil.getSessionFactory().getCurrentSession();
Query query = session.createSQLQuery( "select nextval('schemaName.keySequence')" );
Long key = (Long) query.list().get( 0 );
return key;
Well in case of auto increment generator class, when we use the save() method it returns the primary key (assuming its id). So it returns that particular id, so you can do this
int id = session.save(modelClass);
And return id
I am implementing the asp.net MVC web application, where i am using the Linq to Sql to manipulate the data in database. but in my one of action, i want to insert multiple table entries which are depends upon each other by referring previous insertion Id's. So i just wnat to know how to handle the transaction, like begin transaction, commit,rollback and all like in ADO.net. how to manage this. what if one of insertion get crashed in the middle of manipulation?
Note:- I am not using the Stored procedures here. I am using Lambda expressions and methods. Also these are use in different manager classes.
Example:
For Create Subject - used method in SubjectManager class to insert subject infor, that returns subject Id. within this subjectid i am inserting the let say its chapters with another method in manager class as ChapterManager. which again returns the ChapterId, on base of this chapeter Id , inserting the Topics of chapter. that again uses Topic manager same like above.in each manger class i am creating dataContext object for the same. and I am controlling all this within a single action in my controller. but worrying about the transaction management. how I can use here ?
The DataContext already includes an embedded transaction object. For example, let's say you are placing a new order for a customer. You can set up your model so that the following code updates both the Customer AND Order table with a single SubmitChanges. As long as a foreign key relationship exists between the two tables, the embedded transaction object handles both the Customer update and the Order insert in the same transaction. Using a TransactionScope object to encase a single DataContext is redundant:
using (DataContext dc = new DataContext())
{
Order order = new Order();
order.ProductID = 283564;
order.Quantity = 7;
order.OrderDate = DateTime.Now;
Customer customer = dc.Customers.Single(c => c.CustomerID == 6);
customer.LastUpdate = order.OrderDate;
customer.Orders.Add(order);
dc.SubmitChanges();
}
using(TransactionScope scope = new TransactionScope())
{
using(DataContext ctx = new MyDataContext())
{
ctx.Subject.Add(subject);
Chapter chapter = new Chapter();
chapter.SubjectId = subject.Id;
ctx.SubmitChanges();
ctx.Chapter.Add(chapter);
ctx.SubmitChanges();
scope.Complete() // if it all worked out
}
}
From the System.Transactions namespace I believe.
SQL Server 2008 Ent
ASP.NET MVC 2.0
Linq-to-SQL
I am building a gaming site, that tracks when a particular player (toon) had downed a particular monster (boss). Table looks something like:
int ToonId
int BossId
datetime LastKillTime
I use a 3d party service that gives me back latest information (toon,boss,time).
Now I want to update my database with that new information.
Brute force approach is to do line-by-line upsert. But It looks ugly (code-wise), and probably slow too.
I think better solution would be to insert new data (using temp table?) and then run MERGE statement.
Is it good idea? I know temp tables are "better-to-avoid". Should I create a permanent "temp" table just for this operation?
Or should I just read entire current set (100 rows at most), do merge and put it back from within application?
Any pointers/suggestions are always appreciated.
An ORM is the wrong tool for performing batch operations, and Linq-to-SQL is no exception. In this case I think you have picked the right solution: Store all entries in a temporary table quickly, then do the UPSERT using merge.
The fastest way to store the data to the temporary table is to use SqlBulkCopy to store all data to a table of your choice.
If you're using Linq-to-SQL, upserts aren't that ugly..
foreach (var line in linesFromService) {
var kill = db.Kills.FirstOrDefault(t=>t.ToonId==line.ToonId && t.BossId==line.BossId);
if (kill == null) {
kill = new Kills() { ToonId = line.ToonId, BossId = line.BossId };
db.Kills.InsertOnSubmit(kill);
}
kill.LastKillTime = line.LastKillTime;
}
db.SubmitChanges();
Not a work of art, but nicer than in SQL. Also, with only 100 rows, I wouldn't be too concerned about performance.
Looks like a straight-forward insert.
private ToonModel _db = new ToonModel();
Toon t = new Toon();
t.ToonId = 1;
t.BossId = 2;
t.LastKillTime = DateTime.Now();
_db.Toons.InsertOnSubmit(t);
_db.SubmitChanges();
To update without querying the records first, you can do the following. It will still hit the db once to check if record exists but will not pull the record:
var blob = new Blob { Id = "some id", Value = "some value" }; // Id is primary key (PK)
if (dbContext.Blobs.Contains(blob)) // if blob exists by PK then update
{
// This will update all columns that are not set in 'original' object. For
// this to work, Blob has to have UpdateCheck=Never for all properties except
// for primary keys. This will update the record without querying it first.
dbContext.Blobs.Attach(blob, original: new Blob { Id = blob.Id });
}
else // insert
{
dbContext.Blobs.InsertOnSubmit(blob);
}
dbContext.Blobs.SubmitChanges();
See here for an extension method for this.
How to retrieve identity ID when inserting a row in the db using linq?
If you've set the properties of that "ID" row to "Auto-Generated Value" = true and "Auto-Sync" to "OnInsert"
..... just read it after you've saved the changes using .SubmitChanges(). No special tricks or anything needed....
So in case of the NerdDinner sample:
using(NerdDinnerContext ctx = new NerdDinnerContext())
{
Dinner upcoming = new Dinner();
// set all properties for the dinner
upcoming.EventDate = DateTime.Today.AddDays(30);
ctx.Dinners.InsertOnSubmit(upcoming);
ctx.SubmitChanges();
int newDinnerID = upcoming.DinnerID;
}
Now "newDinnerID" should contain the newly added IDENTITY.
Marc
LINQ to SQL should automatically retrieve the identity of the inserted object, and update the field you mapped to the primary key accordingly - so long as the mapped PK property is marked as [Column(IsDbGenerated=true)].