I have a working solution in place and i m initiating this thread to have a discussion on the best approach.
Environment : EF6, SQL 2012
Scenario:
I have Task and TaskDetail table which have parent child/relationship through TaskID.
Create Method:
While creating a task, i need to ensure an entry is made in TaskDetail table as well.
First approach:
An entry is made into Task Table. SaveChanges. Get the TaskID and assign into the DTO which has the information for Detail table. Pass the DTO to the TaskDetail create Method. Save changes. Commit.. If any error occurs, rollback entire transaction
Second Approach:
Add relavent fields of Task table. Add relevant fields of Task Detail table as well. Add the new detail table object to Task table through the navigation property. Task.Taskdetail.Add(newObj). Finally SaveChanges.
Question 1:
Both the approaches yield same SQL. Couldnt notice much difference though.. But what would be the best approach for doing this???
Question 2:
Also, if you take a look at my scenario, you would have noticed that its SaveAll or SaveNone approach. Initially i tried with looping through DbEntityEntries and then rollbacked the change. But that sounds working for Second approach described above and not for the first approach since i m making a save after my insertion in order to get the TaskID. Then finally i ended up with using "DbConextTransaction" introduced in EF 6. But what is the best approach???
Question 3:
Update Method:
While doing an update , as per my requirement, i will not touch the Task table. It deals with TaskDetail table alone though the task ID would be required which will be passed from the UI.
• Get the existing task detail using the task ID and active flag
(There is one to many relationship)
Update the active flag as false
Create new entry in Task Detail table
I just translated the above statements into code implementation as well but what would be the best approach to handle it????
Related
I have a Case View which shows all the records that were created by the me (My Cases view). I now want to all those Cases edited/modified by me to be visible in that view. The problem is those modified by me could be later modified by the system when a workflow updates the Case, which changes the Modified By User data. Thus, not allowing me to use Modified By (Current User) as a condition for the view.
Is there any other way or condition which I can use to make sure the I can accomplish this?
Thank you in advance.
You may create a new Entity with One to Many relationship with Case Entity. Whenever there is Insert or Update you can add a new record in the mapping entity with Modified By Information and Created On OOB.
You can create a view in the new entity with record modified by Me.
P.S - Single case record will be edited multiple times with multiple users so it will result in high volume of data and may want to look for archiving strategy.
is there a way to rollback a specific change. I have a button that creates a row in two different tables. I want the changes in one of the tables to be rolled back before the committing so that only the second table is committed. How would this be done? Running normal rollback rollbacks both table iterators.
Ive been trying different methods and nothing is working, Please help before I go insane.
find out the corresponding 'VO' row which you want to rollback .
#1. row.setNewRowState(Row.STATUS_INITIALIZED) ;
or
#2. row.revertRow() ;
or
#3. row.remove() ;
The closest thing to rolling back a row would probably be calling refresh on the view row with the appropriate parameters, something like this:
//Obtain app module
DCBindingContainer dcb = (DCBindingContainer) BindingContext.getCurrent().getBindingsEntry();
ApplicationModuleImpl am = (ApplicationModuleImpl) dcb.getDataControl().getDataProvider();
//Get your view
ViewObjectImpl vo = am.getMyView1;
ViewRowImpl row = vo.getCurrentRow(); //alternately use vo.findByKey to lookup a row or simply iterate through every row if dataset is sufficiently small
//rollback the row
row.refresh(Row.REFRESH_REMOVE_NEW_ROWS | Row.REFRESH_UNDO_CHANGES | Row.REFRESH_CONTAINEES);//review modes for ideal combination for use case
Note that rather than a refresh, a row.remove() would probably be sufficient for what it sounds like you are trying to do. In any case, you will need to keep track of the rows you do not want to commit.
While this solution would work, it does not sound ideal for your use case. If you never commit data in the other table, there is no reason to link it to a database table. I would probably do something like one of the following instead:
If the fields are the same in both tables (or similar) and it will be an all-at-once action, create a transient attribute on the ADF view object to denote whether or not the row is approved. Use view criteria on different instances of the view object (add to your application module twice) to display/process the rows you want. Remove not approved rows prior to committing.
If the fields needed are too different or you want to be able to handle one row at a time, make you history view object a programmatic view object with transient attributes, rather than basing it on the table/Entity. When a row is approved remove it from your history view and add it to your approved view.
Before anything, i must say this first: This table design is not my decision. We protest but to no avail, so please don't tell me, don't create a table like that.
We have a database with each table have a flag. This flag used to indicate which environment this row belong to, production or test data.
For server side, we have one variable which currently stored in ThreadLocal to indicate which environment this request belong to, same value as the flag in database.
Our requirement is that if my request belong to test environment then we must select only record belong to this environment. We would need to add a condition to every query we made to database, something like:
SELECT t FROM TABLE t WHERE t.flag = :environment
But we have to update every single query, update every object to set this flag before insert/update into database. This will require a lot of effort as our system already built long ago, not on progress. Also this will bring a lots of risk if someone forgot to add this to any new query.
So is there anyway to insert a condition to check this flag value for every query without have to manually edit the query string? Like an interceptor or something to put this condition in?
Which JPA provider?
With Hibernate, you could try using a #Filter.
Multitenancy could be another option, but probably an overkill in your scenario.
Finally, since you flagged the question with Oracle, perhaps the easiest approach would be to provide dedicated schemas (per environment) with views for every single table in your db, filtered by the flag column. Not sure if you're allowed to do that, though.
With some of the above, you would need a global entity listener to populate the flag field of your entities before they are persisted.
There have been numerous questions posed on this site relating to the retrieval of the IDENTITY after an insert is performed. The way we have been getting the identity is to make the call below, immediately after calling SaveChanges();
context.MyClass.OrderByDescending(c => c.Id).FirstOrDefault();
This seems to work consistently may be completely adequate; however, it has the appearence of opening up a potential for error, should another record be added in between the calls. So the first question is, given that EF performs withing a transacional context, is this method sound?
Secondly, the answer provided to the following question suggests there may be a better way.
Linq to SQL - How to find the the value of the IDENTITY column after InsertOnSubmit()
In that answer, after calling SubmitChanges(), the following call (where "tst" represents the user's class) retrieves the value.
Response.Write("id:" + tst.id.ToString)
This appears to work exactly the same way in LINQ to Entities, where after the call to save changes the instance of the class now includes the id.
context.MyClass.Add(myClass);
context.SaveChanges();
int myNewIdentity = myClass.Id;
Since we are asking for the the actual ID of the class instance (actual record) it would appear to be failsafe. And, it seems logical that the designers of EF should make such basic functionality available. Can anyone confirm that this is proper way to get the identity or at least a best practice?
Yes, LINQ-to-Entities (and LINQ-to-SQL for that matter) will set the generated identity column back in the entity for you after SaveChanges is called. It will also do so for any foreign keys that couldn't be set ahead of time (for instance, a new parent row + a new child row are saved together, and after SaveChanges you'll have the right value in the child row's FK value).
Your particular concern is documented in the 'Working with Entity Keys' page:
http://msdn.microsoft.com/en-us/library/dd283139.aspx
The particular section is 'Entity Keys and Added Objects' and the particular steps are:
4 - If the INSERT operation succeeds, server-generated values are written back to the ObjectStateEntry.
5 - The ObjectStateEntry updates the object with the server-generated value.
I have an custom entity which needs to have a case number for an XRM Application, can I generate a case number from the Service -> Case.
If this is not possible, how can I do this with a plugin, I've looked at the crmnumbering.codeplex.com but this doesn't support 2011, anybody outthere have a solution or should I rewrite it myself?
thanks
I've ran into this same type of issue (I need a custom # for an entity). Here's how you can do it:
Create an Entity called "Counter"
Add a field called "new_customnumber", make it a string or a number depending on what you want
Create a new record for that entity with whatever you want in the new_customnumber field (let's say "10000")
Create a plugin (EntityNumberGenerator) that goes out and grabs that record (you'll probably want to set the security on this record/entity really tight so no one can mess with the numbers)
On Create of the "custom entity" fire the plugin. Grab the value in new_customnumber save it to the "custom entity" (let's say in a "case" field) increment the new_customnumber and save it to the Counter entity.
Warning, I'm not sure how this is with concurrency. Meaning I'm not sure if 2 custom entities being created at the same time can grab the same number (I haven't ran into an issue yet). I haven't figured out a way to "lock" a field I've retrieved in a plugin (I'm not sure it's possible).
You will be unable to create a custom number for custom entities from the normal area you set a case number.
Look at the CRM2011sdk\sdk\samplecode\cs\plug-ins\accountnumberplugin.cs plugin. It's really similar to what you want.
Ry
I haven't seen one for 2011 yet. Probably easiest to write it yourself.
I've always created a database with a table with a single column which is an IDENTITY column. Write an SP to insert, save the IDENTITY value to a variable, and DELETE the row all within a transaction. Return the variable. Makes for a quick and easy plug-in and this takes care of any concurrency issues.
The performance is fast and the impact to your SQL server is minimal.