I'm using an MVC webform to insert a record into a database with several subrecords. In my code-behind I'm first creating a new main record using dataRepository.Add(xx). Now I need to add 5 subrecords that need the ID of the newly created record. How can I retrieve that?
Assuming xx is your model, and its primary key is Id you can get the Id of your inserted record like this:
// at this point xx.Id == null
db.XX.AddObject(xx);
db.SaveChanges();
// now: xx.Id > 0
int id = xx.Id;
If you are using an ORM such as Entity Framework you should be able to create the record and the associated records, link them by adding the associated records into a collection on the main object or setting them somehow and then call the save method on the context. This will do all the linking with ids etc. for you.
How are you doing data access?
You should probably submit all 5 records plus the main one all the way down to your datalayer, performing any validation on the way in your business layer. Then, depending on the implementation of your DL, save the main record, returning the ID, set the parent ID on the subrecords and save them. Do it all within a single transaction and you should be ok.
Please give more info on your data access layer.
If using MS SQL Server, you would use the Scope_Identity() within your stored procedure to get the last identity value inserted into an identity column. See this MSDN article
If using NHibernate you add them within the same session and NHibernate takes care of generating the SQL responsible for inserting the records with the correct Ids.
Related
As an example:
I have two tables in firebird:
TB_CUSTOMER
IDCUSTOMER (autoincrement generator)
CUSTOMERNAME
TB_PHONE
IDPHONE
IDCUSTOMER (foreing key from TB_CUSTOMER)
PHONE
I have a registration form developed in Delphi. The table data TB_PHONE are handled using a dbgrid. I can not assign the value of the field IDCUSTOMER in TB_PHONE, because it was not generated by the Firebird generator. How can I make the relationship between the tables? I want to implement it without first saving the table data TB_CUSTOMER. I'm using datamodules with IBDAC.
Any sugest?
Before detail table can be inserted into, you should have PK-index over master-table updated and having proper master-ID in it. That means that some piece of code should insert master-record before inserting detail-record. Where this piece of code would be - is only limited by your fantasy.
Few arrangements include
insert the master-row in your application. Read the id of the row. Insert detail-row using this id.
read ID from then Generator, then insert both rows (master 1st) using the obtained ID
create a stored procedure, inserting both rows and returning ID (implementing #1 or #2 server-side)
use EXECUTE BLOCK - basically ad hoc anonymous SQL procedure. But that only is available in FB 2.x and except for not using namespace it is inferior to #3.
add BEFORE INSERT trigger onto detail table, searching for ID in master and adding one if not found. This would slow down all insert operations (even when master-ID already exists - that should be checked), would not be able to fill all other master columns but ID and is potentially dangerous due to hiding application logic problems. But still that can be implemented (though ugly and dirty method)
create master-join-detail VIEW and add INSERT trigger for it, propagating the new view-row into both master-table and details-table.
et cetera
I want to implement it without first saving the table data TB_CUSTOMER
There's your problem. You need the primary key from the master table before you can save the detail. That's just the way it works. But if what you want is to make sure that the values get saved together, you can do that as a transaction. In Firebird, you can do it like this:
Begin a transaction. Exactly how you do that depends on which DB library you're using to access your Firebird database.
Run an INSERT INTO ... RETURNING statement to insert the row into your master table and retrieve the generated value as a single operation.
Use the generated PK value to fill in the FK value on your detail table.
Insert the detail row.
Commit the transaction.
I have a web application using EF4. I am somewhat new to EF and now trying to implement change Audit.I tried to do this by trapping the SavingChanges event of the Context Class as below
partial void OnContextCreated()
{
this.SavingChanges += new EventHandler(TicketContainer_SavingChanges);
}
So the event handler accesses the changed records by the following
this.ObjectStateManager.GetObjectStateEntries(
EntityState.Added | EntityState.Modified);
This works fine and I am creating column level audit for selected tables. Every table/entity has an ID field which is an identifier with columnName="ID". So in my audit routine I simply accesses data from column with name "Id" to get the ID of audited record.
The problem I face is during insert . The new record has no ID yet as it is an identity column in the database and is always 0.
One solution I can think of is using GUID for all Ids.But is there a way to implement this using standard int32 Identity Ids?
thanks
When we insert data through EF the identity column is not generted while insertion. To get the Id of Identity columns we have to insert the data first then only we can get the Id of coulmn.
please go through the below which might be helpful to you.
http://www.codeproject.com/KB/database/ImplAudingTrailUsingEFP1.aspx
I don't now how many entities you have but in our own implementation of audit tracking we created a specific audit entity for each entity so we could link them together trough navigational properties and let the database set the identity keys.
If you use inheritance for your audit entities it's quit easy to query them.
Hope this helps :)
Identity columns are not generated while insertion. Once data is inserted then only you can get identity column data in EF. So, you can try some work around by getting Id after insertion and then populating audit table with that Id.
Say I have a generic repository interface as follows:
public interface IRepository<T>
{
Add(T item);
Delete(int itemId);
Update(T item);
}
Typically the new ID of an item added through IRepository.Add() would be determined by some back-end database, but only once the overall transaction/unit of work has been submitted. So I'm fairly certain that it would be wrong for IRepository.Add() to return the new ID of the added item. The repository really shouldn't know anything about how ID are created. Is this correct?
If this is a case how else can one determine the new ID of an item added to a repository, or should I even be doing this? I know an ORM like NHibernate is able to automagically replace objects in memory with new objects with the correct ID, but I'm trying to design my repository with out any specific ORM implementation in mind.
For example say I have a website where customers can make orders. A new customer chooses to check out and is sent to a form to fill out their details. This information is used to create a Customer object which is stored in a CustomerRepository. Now their order information needs to be created but an Order needs to reference a Customer by their ID?
Customer newCustomer = new Customer(first, last, address, phone dateOfBirth);
customerRepository.Add(newCustomer);
//How would I determine customerId??
Order newOrder = new Order(customerId, shippingAddress, billingAddress);
newOrder.AddOrderItem("widget");
newOrder.AddOrderItem("doohicky");
newOrder.AddOrderItem("stuff");
In the example you give, I would create the Customer and Order in one step, and pass domain objects to domain objects, instead of passing Ids:
Customer newCustomer = new Customer(first, last, address, phone dateOfBirth);
// Pass the customer rather than the CustomerId:
Order newOrder = new Order(newCustomer , shippingAddress, billingAddress);
newOrder.AddOrderItem("widget");
newOrder.AddOrderItem("doohicky");
newOrder.AddOrderItem("stuff");
customerRepository.Add(newCustomer);
orderRepository.Add(newOrder);
// SaveChanges()
...when the changes are saved, the framework automatically populates the Ids of both Customer and Order, and fills in Customer.Id, Order.customerId, (etc.) by virtue of the Customer object having been assigned to the Order.
Eric,
In the scenario you mention, I don't see any CommitChanges() going on. I would wrap everything in a transactionscope and then hit customerRepository.CommitChanges() before you add the orderlines. you should then be able to grab the id from the newly created customer object and use it as follows:
Order newOrder = new Order(newCustomer.Id, shippingAddress, billingAddress);
then, if the order(s) fails, you can roll everything back and keep it atomic by not hitting scope.Complete().
hope this helps..
I generate id on a client (a la CombGuid.NewGuid()) and then pass it to constructor. Approach when you are using database identity has serious disadvantages
Whether or not you use NHibernate, I feel that the approach it takes is the right one. Your goal with any domain objects is to only ever have one instance of that object in memory at any one time, i.e. you should never have two objects that represent the same database record. It follows that if the database has updated the record with a new id, the domain object in memory should also be updated with that ID since that is the "one" true representation of that record.
After calling Add, the object's ID is set and you could then make further changes to that object and call Update without having to know too much about your implementation.
Your interface is more DAO than Repository according to DDD:
http://codebetter.com/iancooper/2011/04/12/repository-saveupdate-is-a-smell/
Like Steve Wilkes mentioned, you should keep reference of Customer in Order and not Customer Id so when Unit of Work is processed, it will create correct link those Entities in Persistence Storage (SQL DB, Web Service etc)
For more on DAO here: http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html
Domain entities should have their own ID strategy regardless database IDs, so preferably generate your id in the domain layer, or if you really need to generate id in database, then add another domain identifier generated at domain layer beside the database auto generated id.
In domain driven design where you apply repository pattern you should not tie your domain with database so relying on database for id creation is not a good idea.
Another point is that you may want to make customer associated in order not just putting the customer id, this makes the domain layer rich and solid.
I'm using Entity Framework with an AS.NET MVC application. I need to allow the user to create new records and modify existing ones. I am able to fetch existing records no problem, but when I pass back in the edited entity and try to save it it creates a new one and saves it and leaves the original unmodified.
I am getting the object from EF using the primary key (e.g. ID number for an employee record). I successfully retrieve it, and set the MergeOption like so:
Context.Sector.MergeOption = MergeOption.NoTracking;
I am able to trace that the object has the correct data (using the key of the original record) all the way down to the point where I call:
Context.SaveChanges();
However, after that, the new record is created instead of modifying the existing one.
Is there something obvious I am missing here? I would have thought that retrieving the object and changing some of its values (not the ID) and saving it would just work, but obviously not.
Thanks,
Chris
"NoTracking means that the ObjectStateManager is bypassed and therefore every access to the Entity Objects results in a fetch from the database and the creation of new objects."
-- http://blog.dynatrace.com/2009/03/11/adonet-entity-framework-unexpected-behaviour-with-mergeoptions/
I don't think NoTracking is what you want.
From your comment: "distributed across various tiers and some proprietary libraries"
Are you new()ing up a ObjectContext, closing it or losing the reference to it, and then trying to save your object to a new() or different ObjectContext?
If so your losing all of your change tracking information. If this is the case then you want to call the Attach() method to reattach the entity to the context, ApplyPropertyChanges() and then finally SaveChanges().
Julie Lerman has a pretty good blog post that outlines all the different change tracking options and techniques that are available. You should also check out this MSDN article on the same subject.
Here's my question:
I need to write a wizard, for customers to "create a new" very big objetc, with some other asociated with it: for example, Some images stored in another table (with relationships), some Lat's and Lang's for google earth, etc.
Each of them are stored in diferent tables in the Database, and that's why, i have to first insert to get the first object's Database generated ID to make the relationships with the another Objects. That's the reason I think puttin' Everything on just one View and hide selective DIVs with Jquery is not one of my option.
Session isn't an option because of the bigger object.
And because of the type of website, the wizard MUST be as follows:
Basic details of objetct 1
Images of object 1 (I will need here the ID of the first object)
Geolocations (with google maps, as before)
More details of object 1.
Preview
Publish
The point is, in step 4, user fill some fields that are required by the DB, and I cannot make them nullable as is it part of the customers reqs.
If somebody can a least give Ideas, will be nice...
Thanks in advance
You state that storing your object in Session is not desirable because of the size of the object. An alternative is to serialize that object and store it in the database. As the user progresses through the wizard, that object gets retrieved, updated and stored back in as a blob. Once they publish it, you can insert the appropriate records and remove the serialized object from whatever table you're storing them in.