Currently I am programming an application which saves and deletes entries in a database (code first with entity framework). My question is how can I get the next database id (configured with auto increment - so it added automatically +1).
I tried something like:
var a = databaseContext.MyObject.LastOrDefault().Id;
var myNextDatabaseId = a+1;
This pseudo code is working for most of the cases. But if i had 5 entrees in my database and delete all the five entree's my next database-counter would be 6. When i'm using the code above it will return "null" becouse there is really no entree. But i must get the next database auto increment id.
Is there a possibility which doesn't create a new database entry? Think this shouldn't be necessary.
For example following data construct:
Inserted entry one (internal id = 1)
Inserted entry two (internal id = 2)
Delete entry one
Delete entry two
Read last database entry (entry = null). All data was deleted but I am trying to receive the next auto-increment id 3
Use an explicit transaction scope and identity column. Trying to maintain IDs at the application level isn't scale-able and will be prone to concurrency errors.
Ideally the transaction should span the web service call to roll back automatically if the call fails. With an explicit transaction you can call your context.SaveChanges() which will expose the next ID assigned to the entity, and then roll back if the web service call fails. This can be a transaction managed by the context or TransactionScope.
see: https://msdn.microsoft.com/en-us/library/dn456843(v=vs.113).aspx
Related
I have a Sidekiq worker, which makes an API call, parses the returned json and creates ActiveRecord objects (products). Since the products belong to a brand and the product json also contains the data for the brand, the worker does the following before actually saving the product to the database:
check if the brand exists in the database by checking its unique api_id (the id, with which the brand comes from the api, in the db, there is a unique index on this column);
if it does - fetch its primary id;
if is doesn't - create it and get its primary id
I have implemented this like so:
def brand_id(brand_json)
Brand.where(api_id: brand_json[:api_id]).pluck(:id).first.presence ||
Brand.create!(name: brand_json[:name], api_id: brand_json[:api_id]).id
end
After that the worker creates the product with the brand_id set to the fetched id.
Now I am thinking of the following scenario:
two workers simultaneously fetch data for two products that belong to the same brand that doesn't yes exist in the database;
worker 1 one checks for the brand and doesn't find it;
shortly after that worker 2 checks for the brand and doesn't find it;
worker 1 creates the brand;
Now what happens with worker 2? My assumption - it tries to create the brand, but an error at the database level occurs, as there is already a record with the same api_id? (probably ActiveRecord::RecordNotUnique error is raised?)
Also, how do I handle this case and this type of errors in the context of Sidekiq and ActiveRecord? Should I somehow implement a table-wide lock on the brands table to prevent such things? If yes - than I will not be able to concurrently create products, as at any given time only one worker will have access to the brands table, which is required for creating a product.
Or maybe I should wrap my brand_id(brand_json) method in transaction like so:
def brand_id(brand_json)
ActiveRecord::Base.transaction do
Brand.where(api_id: brand_json[:api_id]).pluck(:id).first.presence ||
Brand.create!(name: brand_json[:name], api_id: brand_json[:api_id]).id
end
end
Please, advise.
Put the unique index constraints (possibly in the form of a multi column index) in the DB.
Just try to create the object. The database will prevent you from making more than one.
Only the thread that succeeded in creating the initial object (no exception occurred) is allowed to proceed with extra processing.
I was creating an EJB application which as a CRUD feature for Hotel Rooms.
I have 4 rows in my Room database.
Now if i remove the 4th row (having room id 104) by using the em.remove() method and then add a new row the table looks like this
A gap is created in the autogenerated sequence Ids. Is there any way to avoid these gaps while adding new rows ?
By default JPA don't have this feature, also this issue is more related how to database manage the sequences and as far as I know sequence number are not reused.
Persist operation will create a new id, when the entity does not have one, if you try to persist a detached object probably you will find a EntityExistsException.
• If the Object is a removed entity instance, an IllegalArgumentException will
be thrown by the merge operation (or the transaction commit will
fail).
I am getting very strange problem. My problem is that this
FIRST am selecting entity from the database using EJB 3.0 and jboss 5.1.0.GA
Subscriber s = (Subscriber)manager.createQuery("SELECT s FROM Subscriber s " +
"WHERE s.subscriber_id = ?1").setParameter(1,123).getSingleResult();
Then I am doing update to the entity with query like this
int a = manager.createQuery(" UPDATE Subscriber s SET s.balance = s.balance + "+10+"WHERE s.subscriber_id = ?1").setParameter(1,123).executeUpdate();
THEN againg I am selecting the entity like this
s = (Subscriber)manager.createQuery("SELECT s FROM Subscriber s " +
"WHERE s.subscriber_id = ?1").setParameter(1,123).getSingleResult();
BUT I am not getting the updated value of "balance" field BUT as soon as I comment the first SELECT statement I am getting the updated value. But I need the first SELECT statement in any case because I want to use it.
Can any one tell me why it is happening and what is its solution?
I would bet this is because of the cache problem.
I will assume that your manager is an EntityManager instance.
You're executing the first query, so the PersistenceContext is fetching the Subscriber entity from the database and puts it into the cache. Then, you're executing batch UPDATE query which directly hits the database omitting the cache structures, so it doesn't affect the PersistenceContext.
At the end, you execute once again the SELECT query. Doing so, the PersistenceContext checks if it have Subscribe entity cached somewhere. It does, so it doesn't hit the database but returns the value stored in its cache.
I don't quite get why you're executing batch UPDATE query instead of just updating your object state and letting the JPA to commit the changes when appropriate.
So instead of:
int a = manager.createQuery("UPDATE Subscriber s SET s.balance = s.balance +
"+10+"WHERE s.subscriber_id = ?1")
.setParameter(1,123).executeUpdate();
you could just do:
// 's' is the Subscribe entity previously fetched from the database
s.setBalance(s.getBalance() + 10);
Although if you still really need to use bach UPDATE then you could try doing
manager.refresh(s);
after the batch UPDATE query. This will let the JPA access the database instead of its cached version.
If you comment the first SELECT statement, the example works because the PersistenceContext didn't cache your entity. It fetches it from the database for the first time just after the batch UPDATE query.
I have three tables Job, Contact and a reference table between them named JobContact. When I delete a record from JobContact table, so record is deleted from database, but it is still present in code. I mean, when I do a select Job by key and when I'm accessing job.JobContact, so record is still there.
How can I force EF to get the current data from this table?
Edited:
I'm using EF to delete the record. Here is a code sample how I'm doing it:
Step 1: delete record from JobContact:
var jobContactRepos = RepositoryFactory.GetRepository<JobContact>();
var jobContact = jobContactRepos.SelectByKey(jobContactId);
jobContactRepos.Delete(jobContact);
jobContactRepos.Save();
Step 2: get the job record from DB after step 1 is done:
var jobRepos = RepositoryFactory.GetRepository<Job>();
var job = jobRepos.SelectByKey(id);
After Step 1, record is deleted from DB: it is OK.
After Step 2, record is still present in the job.JobContact entity: it is not OK.
RepositoryFactory creates already a new context. So I don't understant. In which place in my code should I use Refresh() method?
thanks
You can dispose your EF context and create a new one, this will force EF to get fresh data from the DB instead of using possibly cached data. Alternatively you can call Refresh() on your context using RefreshMode.StoreWins.
But the real question is why do you delete this record from the database directly and don't use EF for it? Had you used the EF context to remove the Contact entity from the Contacts navigation property collection of your Job entity, this problem shouldn't be there in the first place.
Edit:
The reference table should be represented in EF as a navigation property Contacts in your Job entities, and a navigation property Jobs in your Contact entities. Are you using an older version of EF (I am probably not familiar enough with previous versions) or have a custom repository layer that introduces this reference entity?
Is there a way to force the ID value for a new entity in EF when we have an auto-incrementing ID column, i.e. use SET IDENTITY_INSERT behaviour through EF?
Our requirement is that our create form must always show a new, unique ID for the object we're creating on the empty form before it is filled in or saved. The idea is that this ID can be out read to someone over the phone and then the user can complete and save the form after the call is complete. We could reserve an ID by inserting an empty row into the database there and then, but we have unique columns and FKs; instead I've made a 'next ID' table that we increment with locks for safety, and I test this against the top ID in the object table too to be careful. The idea was to then force the use of this new ID when we write back the entity - but I can't see how to get EF to do it.
Is that possible - is it just something I've missed? I don't think the ID even makes it down to the insert so I don't think manually calling SET IDENTITY_INSERT around the SaveChanges would help.
Or do I have to do something else? I can see alternatives:
Change our ID column to not be an identity and take manual control of it all: there's a table ID inheritance here so this is potentially tricky too.
Separate DB ID and user-visible ID into a separate column, and record our unique ID there.
Empty row to reserve the ID, as above; might need some nullability changes, and amending our data read code to ignore these records.
Thanks! This is EF4 (using an EDMX and generated classes not POCOs), and against SQL Server 2008 in case that matters.
Why not use a Guid as primary key. Nothing to do with auto-increment, no concurrency pitfalls etc. You just create the Guid at the moment you create the form. Hand it over to a caller and fill in the form afterwards. When the form is cancelled, no problem. When the form is finished create the entity with the created Guid set the other values of the entity object, apply it to the (a) context and SaveChanges()...
Alternatives that wont alter your schema
Use EF Transaction
You can call context.SaveChanges() and get the autoincremented primary key. Once the process is completed you can commit the transaction. If the transaction is cancelled or there is an error/exception, you can always rollback so you wont have holes/dirty-data in your rows. I suggest you use the singleton pattern and pass the same transaction/context to whatever methods or screens to complete the process.
Just add an additional status: Draft
Save empty form as draft with saved ID, then proceed to edit the form with the information. Once complete save the form as final/ready. If you wont proceed to save the form, you can always recycle the draft.