Query regarding removing and applying ADF view criteria's to view object programmatically - oracle-adf

I have a few questions regarding view criteria's
After removing few applied view criteria's do I need to executeQuery
before applying the same or new view criteria's?
Also after applying each view criteria, do I need to executeQuery?
If the first view criteria I want to apply is applied using testVO.applyViewCriteria(vc); Do I need to unwanted remove view criteria's before or will applyViewCriteria(vc) remove all existing view criteria's?
What I'm trying to do in the below code is to remove any applied view criteria's and then apply new view criteria's that I want to apply.
testVO.getViewCriteriaManager().removeApplyViewCriteriaName("findByvc1");
testVO.getViewCriteriaManager().removeApplyViewCriteriaName("findByvc2");
testVO.getViewCriteriaManager().removeApplyViewCriteriaName("findByvc3");
//testVO.executeQuery();
ViewCriteria vc = testVO.getViewCriteriaManager().getViewCriteria("findByvc1");
VariableValueManager vm = testVO.ensureVariableManager();
vm.setVariableValue("vc1Var", 123);
testVO.applyViewCriteria(vc);
//testVO.executeQuery();
ViewCriteria vc1 = testVO.getViewCriteriaManager().getViewCriteria("findByvc3");
vm.setVariableValue("vc3Var", "test");
testVO.applyViewCriteria(vc1, true);
testVO.executeQuery();

Here's an article where I discuss how to apply view criteria programmatically in Oracle ADF : https://cedricleruth.com/how-to-apply-a-viewcriteria-programmatically-in-adf/ Code extract :
/**
* Apply view criteria named MyViewCriteria to it's ViewObject
* by getting it through the binding iterator MyViewObjectIterator
*/
public void applyViewCriteriaOnViewObjectByIteratorName(String MyViewCriteriaName, String MyViewObjectIteratorName) {
try {
//Get The viewObject from the iterator define in the current binding context
ViewObject vo = this.getViewObjectFromIteratorName(MyViewObjectIteratorName)
//Get all it's ViewCriteria using the ViewCriteriaManager of the ViewObject
ViewCriteriaManager vcm = vo.getViewCriteriaManager();
//Get the specified View Criteria
ViewCriteria vc = vcm.getViewCriteria(MyViewCriteriaName);
//Apply the ViewCriteria to the ViewObject
vo.applyViewCriteria(vc);
//Note: If you need to apply this view criteria on top of already applied view criteria
//without removing them you can add the following boolean parameter :
//vo.applyViewCriteria(vc,true);
//That's all you need if the iterator is set to be refresh after this
//If not you can force the ViewObject to execute by uncommenting the following :
//vo.executeQuery();
} catch (NullPointerException e) {
//Log and warn for null
//Often occur when there is an error in the provided attributes
//(MyViewCriteriaName, MyViewObjectIteratorName)
} catch (Exception e) {
//Log and warn for other exceptions - Should never be needed
}
/**
* Useful function to get ViewObject from IteratorName
* The iterator need to have a least one binding define in the current page
* In this gist it's a private but i advice setting it as a public static in an utility class available for the whole Controller
*/
private ViewObject getViewObjectFromIteratorName(String MyViewObjectIteratorName) {
ViewObject vo = null;
try {
DCBindingContainer bindings = (DCBindingContainer) BindingContext.getCurrent().getCurrentBindingsEntry();
DCIteratorBinding iterator = bindings.findIteratorBinding(MyViewObjectIteratorName);
vo = iterator.getViewObject();
} catch (NullPointerException e) {
//Log and warn for null
//Often occur when there is an error in the provided attributes
//or if the iterator doesn't have a least one binding define in the current page
}
return vo;
}
To answer your questions :
You do not need to executeQuery() if your vo is already set to be refreshed. If you have a ppr on the iterator for example. If not you need to executeQuery to force refresh your iterator.
You do not need to executeQuery after each applyViewCriteria especially as you use the secondary boolean argument to true which "apply this view criteria on top of already applied view criteria". They will all apply over each other as layers and be set when you executeQuery at the end.
If you do not add the secondary boolean argument as true, your view criteria will be the only one applied and all others would be automatically removed.

Related

getting error when trying to read from DataGridView with event handler winform

I have a winform that has a gridview that I am applying data to via a Dataset. When the data binds, it calls the SelectionChanged event handler. I researched that and found a way around it by adding an if clause to see if the DGV has focus (all other resolutions did not work that I found). That part is working as planned. When I step through the program, the event handler tries to go through the code 3 times when it binds the data. The if clause stops it from reaching the code. My issue is after the data binds and I then choose a row in the DGV, the event handler then throws "An unhandled exception of type 'System.ArgumentOutOfRangeException' occurred in mscorlib.dll". When stepping through the code, the DGV is returning the proper row index to my 'int row' variable, but the code I use to get the row/cell info throws the error before it applies it to the 'loadtableID' variable. I need help. You can ignore the second DGV in the top. It takes the selected row's info and gets another DB table info. Also, if it helps, I did not apply a datasource to the program or create datasets for each individual dataset that is returned, I am using the system's generic Dataset when returning data.
private void gvMainSelectResults_SelectionChanged(object sender, EventArgs e)
{
if (gvMainSelectResults.Focused)
{
gvMainArchiveResults.DataSource = null; //second DGV that is populated later and everytime is cleared with a new selection
loadTableID = 0;
orgID = 0;
dbFileName = "";
sourceType = "";
int row = gvMainSelectResults.CurrentCell.RowIndex;
loadTableID = Convert.ToInt32(gvMainSelectResults.SelectedRows[row].Cells["LoadTableID"].Value); //this is where I get the error, even if the "int row" has the correct index number
orgID = Convert.ToInt32(gvMainSelectResults.SelectedRows[row].Cells["OrganizationID"].Value);
dbFileName = Convert.ToString(gvMainSelectResults.SelectedRows[row].Cells["FileName"].Value);
sourceType = Convert.ToString(gvMainSelectResults.SelectedRows[row].Cells["SourceType"].Value);
more code here...
You are using the RowIndex value to get your text from the SelectedRows collection.
But this collection contains only
Gets the collection of rows selected by the user.
This means that the collection contains only a subset of the rows present in your grid. When RowIndex is 2 and you have just one row in the SelectedRows collection you get the OutOfRange exception.
With the RowIndex value you should refer to the Rows collection instead
loadTableID = Convert.ToInt32(gvMainSelectResults.Rows[row].Cells["LoadTableID"].Value);
orgID = Convert.ToInt32(gvMainSelectResults.Rows[row].Cells["OrganizationID"].Value);
dbFileName = Convert.ToString(gvMainSelectResults.Rows[row].Cells["FileName"].Value);
sourceType = Convert.ToString(gvMainSelectResults.Rows[row].Cells["SourceType"].Value);

how to get rows what I want in ADF

How do get this simple task done in ADF -
Based on some parameter I want a row to be retrieved from a view object programmatically. I have no idea how this could be done. IF I am not using ADF my business method would have a query like below and then return whatever details i want in the form on object.
*select * from abcTable where abccolumn = param1;*
param1 is an input from a jsf page. I capture that input and based on that input i need to query another database table (which will be in the form of View object in the ADF) to retrieve additional details and fill up some other components in the jsf page. How do I get this task done. I am trying to get instance of the view object but i do not seem to find any method using which I could retrieve only limited rows i want based on a where clause. The executeQuery method does not return anything (weird case).
You can filter viewObject programmatically and can get rows-
you can filter viewObject using 2 methods
1. where clause
2. filterdRows
see- Get Filtered Rows From View Object in Oracle ADF
The VO has a setWhereClause method that you can use to add/modify a where clause to the query.
You can also pre-define a VO with a bind parameter query.
Some more info on the UI side :
ADF Query with Parameters and List of Values and
ADF Query with Parameters and List of Values - Part II
Bind that parameter to a variable in your bean. Let's say you want
to search the value from and input text:
On page:
<af:inputText id="it8" binding="#{pageFlowScope.<YOURBEAN>.inputSearchBox}"/>
In your bean:
private RichInputText inputSearchBox;
public void setInputSearchBox(RichInputText inputSearchBox) {
this.inputSearchBox= inputSearchBox;
}
public RichInputText getInputSearchBox() {
return inputSearchBox;
}
Make a method in the bean that would do the search:
On page:
<af:commandButton text="search" id="cb6" actionListener="#{pageFlowScope.<YOURBEAN>.search}"/>
In bean:
public void search(ActionEvent actionEvent) {
}
In this method you will need to get the ViewObject from AppModuleImpl:
BindingContext bindingContext = BindingContext.getCurrent();
DCDataControl dc =bindingContext.findDataControl("YOURAPPMODULEDATACONTROL");
AppModuleImpl appM = (AppModuleImpl )dc.getDataProvider();
ViewObjectImpl vo = appM.getYourVO();
Create and apply a view criteria on that viewObject with the text that you entered in the input:
String searchValue = null;
//get the value from the search field
if (inputSearchBox.getValue() != null) {
searchValue = inputSearchBox.getValue().toString();
}
ViewCriteria vc = vo.createViewCriteria();
ViewCriteriaRow vcRow = vc.createViewCriteriaRow();
vcRow.setAttribute("Field you want to search by", searchValue);
vc.addRow(vcRow);
vo.applyViewCriteria(vc);
vo.executeQuery();
Now the ViewObject is filtered by your search value.
If you want to go through the result and save some VO values from that line you found you would need to make a row iterator, iterate through it and store the values you need in some variables:
RowSetIterator rsi = vo.getRowSetIterator();
String valueToGet = null;
while (rsi.hasNext()){
Row r = rsi.next();
valueToGet = (String)r.getAttribute("<WHAT ATTRIBUTE YOU WANT TO GET>");
}

linq reflection WInForms

I am very new to linq and am trying to figure out how to accomplish the following:
Currently, I have a Winforms project that has a Base Form with a DataRow as one of it's members. I have several derived Forms populate the DataRow based on data from a DataTable (SQL Query Result). There are controls on the derived Forms that are populated with the values from the data as well. When the Save button on the derived Forms is clicked, the DataRow in the Base Form is updated and then the Derived Form updates the Database via a DataAdapter.
I wanted to replace all of the SQL Commands using linqs so I tried implementing this functionality using LINQ by the following:
I created my Linq query in the Derived Form and assigned the result to an Object in the Base Form. I cast the Object in the Base Form to the class type of the Linq query and use reflection to populate all the controls on the Derived Form. When the save button is clicked I update the Object but I am not able to update the Database.
The problem that I can't solve is how to update the database once the object is updated. At this point I don't have the Data Context that I used for the linq query.
I am using an SQL function within the linq query so I had to create a separate class for these values as I was getting an anonymous type error. I am probably missing something here.
Any help would be most appreciated as I really how clean the linq code is.
Edit (Copied from Brad's Edit to Tomas's answer):
Here are the 3 steps of my code.
Step 1 - Get a singe record of data from database
private void GetDatabaseDetailData()
{
_db = new PriorityDataContext();
DetailData = (from db in _db.tblDatabases
where db.DatabaseID == Id
select db).SingleOrDefault();
DeveloperData = (from db in _db.tblDatabases
where db.DatabaseID == Id
select new DeveloperInfo
{
DeveloperName = _db.func_get_employee_name(db.Developer)
}).SingleOrDefault();
}
Step 2 - Populate all controls whos name exists in the Object. The DetailData Object is cast to the specific type passed into this method. All code not shown for brevity.
protected virtual void PopulateDetailControlsA(List<Control> controlContainers, string srcDataTableName)
{
Object data = null;
Type type = null;
switch (srcDataTableName)
{
case "tblDatabases" :
type = typeof(tblDatabase);
data = (tblDatabase)DetailData;
break;
}
if (type != null)
{
var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var controlContainer in controlContainers)
{
foreach (var propertyInfo in properties)
{
if (!ControlExists(controlContainer, propertyInfo.Name)) continue;
var txtControl = controlContainer.Controls[propertyInfo.Name] as ExtendedTextBox;
if (txtControl != null)
{
try
{
var value = propertyInfo.GetValue(data, null).ToString();
if (propertyInfo.Name == "row_oper_name" || propertyInfo.Name == "row_last_chng_oper_name")
{
txtControl.Text = RowOperatorData.RowOperatorName;
txtControl.ValueMember = propertyInfo.GetValue(data, null).ToString();
}
else
txtControl.Text = value;
}
catch (NullReferenceException)
{
}
continue;...........
Step 3 - Try and save changes back to database in the derived From.
private void SaveData()
{
try
{
_db.SubmitChanges();
}
catch (Exception sqlException)
{
}
}
What I am really unclear about hear is how to store the result set in the Base Form so that I can use the same code for many different queries. The DataRow worked great because I use the some code for over 25 derive Forms.
If I understand you correctly, you create the DataContext in a derived form and then use it to write some queries (in a derived form). In order to be able to update the database, your queries must return the entities obtained from the table (i.e. the select clause should just return the entity). For example:
DataContext db = // ...
var q = from p in db.Things
where p.Some > 10 select p;
If you then modify the entities, you can use db.SubmitChanges() to store the changes (made to the entity objects) to the database. For this, you need the original db value.
In your scenario, you'll need to store the DataContext (as a field) in the derived form. If you need to perform the update from the base form, then I suggest you define a virtual method:
// Base form
protected abstract void UpdateDatabase();
// Derived from with field 'db' storing 'DataContext'
protected override void UpdateDatabase() {
db.SumbitChanges();
}

WPF - Viewmodel - Binding errors while refreshing data

I have a MVVM pattern test application that is tossing a lot of
System.Windows.Data Error: 17 : Cannot get 'Item[]' value (type 'ChuteGroup') from 'Groups' (type 'ChuteGroupsModel'). BindingExpression:Path=Groups[0]; DataItem='MainViewModel' (HashCode=41802290); target element is 'ChuteView' (Name=''); target property is 'DataContext' (type 'Object') ArgumentOutOfRangeException:'System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values. Parameter name: index'
This happens when I enter my "onRefresh" routine in the viewmodel. I have an observable collection called "Current" and the first thing I do in the refresh routine is clear the entries from the Current collection. I then get a slew of these data error 17 messages because I think in the background the bindings are trying to update and now there isn't anything in the collection until I re-fill and re-create each entry into the observable collection.
Is there a better way of doing this? Runtime performance doesn't seem to be affected by this but I don't like errors in my output window. I found that if I didn't clear the collection it just doubled in size each time the viewmodel refreshed itself. Since this collection is used in conjunction with 54 UI elements, which are binded by index, the collection can't double in size or everything wont point to the correct UI element.
private void FetchData()
{
ChuteGroupsModel.isDuringRefresh = true;
DataSet sqldata = new DataSet();
SqlConnection conn = new SqlConnection("Data Source=(local);Initial Catalog=ScratchPaper;User ID=somecacct;Password=somepassword;Connect Timeout=5");
SqlCommand cmd = new SqlCommand("Select chuteGroup, chuteGroupDef, TotalChutes, UpPackWave, UpColorId, UpPackWaveTS, DownPackWave, DownColorId, DownPackWaveTS from ChuteGroups Order by chuteGroup asc",conn);
SqlDataAdapter da = new SqlDataAdapter(cmd);
try
{
da.Fill(sqldata);
}
catch (Exception Ex){ MessageBox.Show(Ex.ToString());}
//DataSet sqldata = this.DataLayer.getDataSet("Select * from AvailableColors Order by ID asc", CommandType.Text, null);
foreach (DataRow row in sqldata.Tables[0].Rows)
{
ChuteGroup group = new ChuteGroup((int)row.ItemArray[0], (string)row.ItemArray[1], (int)row.ItemArray[2], (string)row.ItemArray[3],(string)row.ItemArray[4], (DateTime)row.ItemArray[5], (string)row.ItemArray[6], (string)row.ItemArray[7], (DateTime)row.ItemArray[8]);
Add(group);
}
ChuteGroupsModel.isDuringRefresh = false;
}
private void onRefresh(object sender, System.EventArgs e)
{
try
{
if (ChuteGroupsModel.isDuringRefresh)
{
return;
}
Refresh();
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message.ToString());
}
}
public void Refresh()
{
Current.Clear(); //Current is a static reference to my collection
FetchData();
}
You are right in assuming that the binding errors are due to your collection being cleared. As you aren't experiencing any performance penalties, I wouldn't worry about it too much.
If you are really annoyed by them, you can create a new observable collection type to allow you to set the new values. If you crack open the ObservableCollection class in Reflector, you'd copy the implementation, and add one new method like so:
public class ObservableList<T> : Collection<T>, INotifyCollectionChanged, INotifyPropertyChanged
{
// ObservableCollection implementation here
...
public void SetItems(IEnumerable<T> items)
{
this.CheckReentrancy();
base.ClearItems();
int i = 0;
foreach (var item in items)
{
base.InsertItem(i, item);
++i;
}
this.OnPropertyChanged("Count");
this.OnPropertyChanged("Item[]");
this.OnCollectionReset();
}
}
Then, instead of clearing your data and adding it one row at a time, you'd call the SetItems method.
I know it's been a while since this question has been asked, but one method that has solved this type of issue for me is using RemoveAt(0) (and/or whatever locations you need cleared) and subsequently Adding your data to the collection. There seems to be some sort of timing issue with Clear() in that for a few brief instants, calls from the bindings for the data returns an empty collection, thus the output messages. This may seem a bit detailed and perhaps brutish in comparison with a more generic clear, but it does remove the errors and noticeably improves performance.

Refreshing BindingSource after insert (Linq To SQL)

I have a grid bound to a BindingSource which is bound to DataContext table, like this:
myBindingSource.DataSource = myDataContext.MyTable;
myGrid.DataSource = myBindingSource;
I couldn't refresh BindingSource after insert. This didn't work:
myDataContext.Refresh(RefreshMode.OverwriteCurrentValues, myBindingSource);
myBindingSource.ResetBinding(false);
Neither this:
myDataContext.Refresh(RefreshMode.OverwriteCurrentValues, myDataContext.MyTable);
myBindingSource.ResetBinding(false);
What should I do?
I have solved the problem but not in a way I wanted.
Turns out that DataContext and Linq To SQL is best for unit-of-work operations. Means you create a DataContext, get your job done, discard it. If you need another operation, create another one.
For this problem only thing I had to do was recreate my DataContext like this.dx = new MyDataContext();. If you don't do this you always get stale/cached data. From what I've read from various blog/forum posts that DataContext is lightweight and doing this A-OK. This was the only way I've found after searching for a day.
And finally one more working solution.
This solution works fine and do not require recreating DataContext.
You need to reset internal Table cache.
for this you need change private property cachedList of Table using reflection.
You can use following utility code:
public static class LinqDataTableExtension
{
public static void ResetTableCache(this ITable table)
{
table.InternalSetNonPublicFieldValue("cachedList", null);
}
public static void ResetTableCache(this IListSource source)
{
source.InternalSetNonPublicFieldValue("cachedList", null);
}
public static void InternalSetNonPublicFieldValue(this object entity, string propertyName, object value)
{
if (entity == null)
throw new ArgumentNullException("entity");
if(string.IsNullOrEmpty(propertyName))
throw new ArgumentNullException("propertyName");
var type = entity.GetType();
var prop = type.GetField(propertyName, BindingFlags.NonPublic | BindingFlags.Instance);
if (prop != null)
prop.SetValue(entity, value);
// add any exception code here if property was not found :)
}
}
using something like:
var dSource = Db.GetTable(...)
dSource.ResetTableCache();
You need to reset your BindingSource using something like:
_BindingSource.DataSource = new List();
_BindingSource.DataSource = dSource;
// hack - refresh binding list
Enjoy :)
Grid Data Source Referesh by new query instead just Contest.Table.
Simple Solution < But Working.
Whre is eg.
!!!!! Thanks - Problem Solved after no of days !!! but with so simple way ..
CrmDemoContext.CrmDemoDataContext Context = new CrmDemoContext.CrmDemoDataContext();
var query = from it in Context.Companies select it;
// initial connection
dataGridView1.DataSource = query;
after changes or add in data
Context.SubmitChanges();
//call here again
dataGridView1.DataSource = query;
I have the same problem. I was using a form to create rows in my table without saving the context each time. Luckily I had multiple forms doing this and one updated the grid properly and one didn't.
The only difference?
I bound one to the entity similarly (not using the bindingSource) to what you did:
myGrid.DataSource = myDataContext.MyTable;
The second I bound:
myGrid.DataSource = myDataContext.MyTable.ToList();
The second way worked.
I think you should also refresh/update datagrid. You need to force redraw of grid.
Not sure how you insert rows. I had same problem when used DataContext.InsertOnSubmit(row), but when I just inserted rows into BindingSource instead BindingSource.Insert(Bindingsource.Count, row)
and used DataContext only to DataContext.SubmitChanges() and DataContext.GetChangeSet(). BindingSource inserts rows into both grid and context.
the answer from Atomosk helped me to solve a similar problem -
thanks a lot Atomosk!
I updated my database by the following two lines of code, but the DataGridView did not show the changes (it did not add a new row):
this.dataContext.MyTable.InsertOnSubmit(newDataset);
this.dataContext.SubmitChanges();
Where this.dataContext.MyTable was set to the DataSource property of a BindingSource object, which was set to the DataSource property of a DataGridView object.
In code it does looks like this:
DataGridView dgv = new DataGridView();
BindingSource bs = new BindingSource();
bs.DataSource = this.dataContext.MyTable; // Table<T> object type
dgv.DataSource = bs;
Setting bs.DataSource equals null and after that back to this.dataContext.MyTable did not help to update the DataGridView either.
The only way to update the DataGridView with the new entry was a complete different approach by adding it to the BindingSource instead of the corresponding table of the DataContext, as Atomosk mentioned.
this.bs.Add(newDataset);
this.dataContext.SubmitChanges();
Without doing so bs.Count; returned a smaller number as this.dataContext.MyTable.Count();
This does not make sense and seems to be a bug in the binding model in my opinion.

Resources