How to validate a calculated column on an ADO.NET DataTable - winforms

According to MS, calculated columns (AKA expression columns) don't raise any DataTable events:
http://msdn.microsoft.com/en-us/library/w9y9a401%28v=vs.80%29.aspx,
This makes it impossible to use the DataTable.ColumnChanging event to validate the value of such column by using the technique documented at:
http://msdn.microsoft.com/en-us/library/ms171930%28v=vs.80%29.aspx
I'd like to know if someone has thought of a way to add some form of validation to such calculated columns so that it will work with the standard ErrorProvider control on a Windows Form ?
Thank you

Assuming you use bindingsource:
private void Asignar_Columna_Balance()
{
if (cataciones_BindingSource.Current == null) return;
var _fila_Actual = ((cataciones_BindingSource.Current as DataRowView).Row as DataSet_SKNCC_Reportes.REPORTE_CATACIONESRow);
if ((cataciones_BindingSource.Current as DataRowView).IsNew)
_fila_Actual["BALANCE"] = (_fila_Actual.AROMA + _fila_Actual.ACIDEZ + _fila_Actual.CUERPO + _fila_Actual.SABOR).ToString();
else
{
//FORCE REBINDING!!! PARA QUE FUNCIONE AL EDITAR UN BINDINGDOURCE!!!!
cataciones_Tabla_Lote.Columns["BALANCE"].Expression = null;
cataciones_Tabla_Lote.Columns["BALANCE"].Expression = "Aroma + Acidez + Cuerpo + Sabor";
}
//balance_Mask.Text = (_fila_Actual.AROMA + _fila_Actual.ACIDEZ + _fila_Actual.CUERPO + _fila_Actual.SABOR).ToString();
}

Related

How to report a value in real time in Fink?

I want three values, they are aggValueInLastHour aggValueInLastDay aggValueInLastThreeDay.
I've tried like below.
But I don't want to wait, means that I'm not prefer to use sliding window to do aggregation.(3 day window must wait three days' data, this is unbearable for our system.)
How can I get last 3 day aggregation value when first event come?
Thanks for any advice in advance!
If you want to get more frequent updates you can use QueryableState, polling the state at a rate that suits your use case.
You can make use of the ContinuousEventTimeTrigger, which will cause your window to fire on a shorter time period than the the full window, allowing you to see the intermediate state. You can optionally wrap that in a PurgingTrigger if the downstream consumers of your sink are expecting each output to be a partial aggregation (rather than the full current state) and sums them up.
I've tried CEP.
code:
AfterMatchSkipStrategy strategy = AfterMatchSkipStrategy.skipShortOnes();
Pattern<RiskEvent, ?> loginPattern = Pattern.<RiskEvent>begin("start", strategy)
.where(eventTypeCondition)
.timesOrMore(1)
.greedy()
.within(Time.hours(1));
KeyedStream<RiskEvent, String> keyedStream = dataStream.keyBy(new KeySelector<RiskEvent, String>() {
#Override
public String getKey(RiskEvent riskEvent) throws Exception {
// key by user for aggregation
return riskEvent.getEventType() + riskEvent.getDeviceFp();
}
});
PatternStream<RiskEvent> eventPatternStream = CEP.pattern(keyedStream, loginPattern);
eventPatternStream.select(new PatternSelectFunction<RiskEvent, RiskResult>() {
#Override
public RiskResult select(Map<String, List<RiskEvent>> map) throws Exception {
List<RiskEvent> list = map.get("start");
ArrayList<Long> times = new ArrayList<>();
for (RiskEvent riskEvent : list) {
times.add(riskEvent.getEventTime());
}
Long min = Collections.min(times);
Long max = Collections.max(times);
Set<String> accountList = list.stream().map(RiskEvent::getUserName).collect(Collectors.toSet());
logger.info("时间范围:" + new Date(min) + " --- " + new Date(max) + " 事件:" + list.get(0).getEventType() + ", 设备指纹:" + list.get(0).getDeviceFp() + ", 关联账户:" + accountList.toString());
return null;
}
});
maybe you notice that, the skip strategy skipShortOnes is a customized strategy.
Show you my modification in CEP lib.
add strategy in Enum.
public enum SkipStrategy{
NO_SKIP,
SKIP_PAST_LAST_EVENT,
SKIP_TO_FIRST,
SKIP_TO_LAST,
SKIP_SHORT_ONES
}
add access method in AfterMatchSkipStrategy.java
public static AfterMatchSkipStrategy skipShortOnes() {
return new AfterMatchSkipStrategy(SkipStrategy.SKIP_SHORT_ONES);
}
add strategy actions in discardComputationStatesAccordingToStrategy method at NFA.java.
case SKIP_SHORT_ONES:
int i = 0;
List>> tempResult = new ArrayList<>(matchedResult);
for (Map> resultMap : tempResult) {
if (i++ == 0) {
continue;
}
matchedResult.remove(resultMap);
}
break;

Dynamically setting DataGridViewComboBoxCell's DataSource to filtered DataView based off of other cell selection

I have been looking high and low for a way to do the following, but to no avail. I came up with a solution that works, but am wondering if there is a better way of handling it.
The Problem:
I am using a DataGridView that has two DataGridViewComboBoxColumn, col1 and col2.
col1 has had its DataSource set to a DataTable. Based off of the selection from a given cell in col1, I would like to have the respective col2 cell in the same row have its DataSource set to be a filtered DataView of col2's DataSource.
The abbreviated code from my current implementation might better help describe what I am trying to do:
DataGridView dg = new DataGridView();
dg.DataSource = new BindingSource() { DataSource = _myDataTable }; //DataTable with Foreign Keys for ID1 and ID2
dg.CellValueChanged += new DataGridViewCellEventHandler(dg_CellValueChanged);
DataGridViewComboBoxColumn col1 = new DataGridViewComboBoxColumn();
col1.DataPropertyName = "ID1";
col1.DisplayMember = "Display1";
col1.ValueMember = "ID1";
col1.DataSource = dataTable1;
col1.ValueType = typeof(Int32);
DataGridViewComboBoxColumn col2 = new DataGridViewComboBoxColumn();
col2.DataPropertyName = "ID2";
col2.DisplayMember = "Display2";
col2.ValueMember = "ID2";
col2.DataSource = dataTable2;
col2.ValueType = typeof(Int32);
dg.Columns.Add(col1);
dg.Columns.Add(col2);
Then I define the event handler as:
private void dg_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex == 0 && e.RowIndex > -1)
{
var dgv = sender as DataGridView;
if (dgv == null)
return;
int selectedID;
if (!int.TryParse(dgv[e.ColumnIndex, e.RowIndex].Value.ToString(), out selectedID))
return;
var cell = dgv[e.ColumnIndex + 1, e.RowIndex] as DataGridViewComboBoxCell;
if (cell == null)
return;
var col = dgv.Columns[e.ColumnIndex + 1] as DataGridViewComboBoxColumn;
if(col == null)
return;
var dt = col.DataSource as DataTable; // The macro-DataTable containing all possible values
if(dt == null)
return;
DataView dv = new DataView(dt, "ID1 = " + selectedID, "DisplayOrder", DataViewRowState.CurrentRows);
if(dv.Count == 0)
return;
//This is the part that I am wondering if there is a better way of handling
cell.DataSource = dt; //Set the data source to the macro-DataTable so that when we set the Value to something in the new DataView it will not throw an exception
cell.DisplayMember = "Display2"; // Have to redefine the Display/Value members
cell.ValueMember = "ID2";
cell.Value = dv[0]["ID2"]; // Set the value to the first option in the new DataView to avoid an exception being thrown when setting the dv as the DataSource
cell.DataSource = dv;
}
}
The last part is my concern.
When dynamically switching the DataSource of cell2, if cell2's current selection doesn't appear in the new DataView, then an exception will be thrown:
System.ArgumentException: DataGridViewComboBoxCell value is not valid.
To avoid that, I am setting the datasource to the macro-DataTable (containing all of the values that could be shown based off of cell1's selection), changing the selected value of cell2 to be the first result in the DataView and then setting cell2's DataSource to be said DataView. This all ensures that the cell is never going to have an invalid selection and it works as expected.
My question is, is there a better/simpler way of doing this? For my use, this code is only activated when creating new rows, so it isn't being done more than a few times in the given form. However, if there is a better way of doing it or some suggestions on making it better, I would appreciate it!
(first question here, so I am also open to suggestions for posting ... apologies for any missteps)
EDIT (providing table structure - also changed "BoundID" to be "ID1" to avoid confusion):
DataGrid's table structure would be:
MainTableID int
ID1 int --This is a foreign key to col1
ID2 int --This is a foreign key to col2
Column 1's table structure:
ID1 int
Display1 varchar(50)
Column 2's table structure:
ID2 int
Display2 varchar(50)
ID1 int --This is a foreign key to col1
Updated:
I have redefined the CellValueChanged event handler per Mohsen's suggestions:
private void dg_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex == 0 && e.RowIndex > -1)
{
var dgv = sender as DataGridView;
var cell = dgv[e.ColumnIndex + 1, e.RowIndex] as DataGridViewComboBoxCell;
if (cell == null)
return;
DataView dv = new DataView( ((DataTable)((DataGridViewComboBoxColumn)dgv.Columns[e.ColumnIndex + 1]).DataSource), "ID1 = " + dgv.CurrentCell.Value, "DisplayOrder", DataViewRowState.CurrentRows);
if(dv.Count == 0)
return;
cell.DisplayMember = "Display2"; // Have to redefine the Display/Value members
cell.ValueMember = "ID2";
cell.DataSource = dv;
}
}
And I have added in an event handler for the DataError like he suggested:
void dg_DataError(object sender, DataGridViewDataErrorEventArgs e)
{
if(e.ColumnIndex != 1)
{
//Alert the user for any other DataError's outside of the column I care about
MessageBox.Show("The following exception was encountered: " + e.Exception);
}
}
This seems to work perfectly.
Your code can be simplified to this with no exception throwing:
if (e.ColumnIndex == 0 && e.RowIndex > -1)
{
var dgv = sender as DataGridView;
var cell = dgv[e.ColumnIndex + 1, e.RowIndex] as DataGridViewComboBoxCell;
if (cell == null)
return;
cell.DataSource = ((DataTable)((DataGridViewComboBoxColumn)dgv.Columns[e.ColumnIndex + 1]).DataSource).Select("BoundID = " + dgv.CurrentCell.Value);
}
Updated
When you change an already set item in first combo box since the filtered dataview in the second combobox have different ID1, an exception is thrown with "DataGridViewComboBoxCell value is not valid.". In order to catch this exception register datagridview DataError event with no code in the registered method. Then when you change the already set combbox, the corresponding combobox will be filled with correct items.
This is the quick stop shop for the solution that worked for me, but I still wanted to give Mohsen the credit. Duplicated this in the original question.
I have redefined the CellValueChanged event handler per Mohsen's suggestions:
private void dg_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex == 0 && e.RowIndex > -1)
{
var dgv = sender as DataGridView;
var cell = dgv[e.ColumnIndex + 1, e.RowIndex] as DataGridViewComboBoxCell;
if (cell == null)
return;
DataView dv = new DataView( ((DataTable)((DataGridViewComboBoxColumn)dgv.Columns[e.ColumnIndex + 1]).DataSource), "ID1 = " + dgv.CurrentCell.Value, "DisplayOrder", DataViewRowState.CurrentRows);
if(dv.Count == 0)
return;
cell.DisplayMember = "Display2"; // Have to redefine the Display/Value members
cell.ValueMember = "ID2";
cell.DataSource = dv;
}
}
And I have added in an event handler for the DataError like he suggested:
void dg_DataError(object sender, DataGridViewDataErrorEventArgs e)
{
if(e.ColumnIndex != 1)
{
//Alert the user for any other DataError's outside of the column I care about
MessageBox.Show("The following exception was encountered: " + e.Exception);
}
}
This seems to work perfectly.

Select element in WPF Combobox from Nhibernate

I have a dude, i want to select a value from wpf Combobox
I have the next code:
private void CargarUnidades()
{
List<Unidades> unidades;
using (var sesion = NHibernateFluentConfiguracion.AbrirSesion())
{
using (var transaccion = sesion.BeginTransaction())
{
unidades = Unidades.ObtenerTodaslasUnidades();
}
}
cmbUnidad.ItemsSource = unidades;
cmbUnidad.DisplayMemberPath = "Nombre";
cmbUnidad.SelectedValuePath = "Nombre";
}
After I charge the unidades
CargarUnidades(); //Charge all unidades in the combobox
Articulos c = Articulos.Obtener(id_articulo);
//Get Articulo from the database for the id
//In the last query I get the unidad same that exists in cmbUnidad
//previusly charge
//I assing the value but in the combobox doesnt appear selected,
//appear nothing
cmbUnidad.SelectedValue = c.id_unidad;
txtCodigo.Text = c.Codigo;
.
.
.
.
How I can select a value from combobox???
Note: I m new in WPF and my english is not good je je je
Thanks for the answer Firo, I modify the code and this is the result
cmbUnidad.Items.Cast<Unidades>().FirstOrDefault(u => u.id_unidad == c.id_unidad.id_unidad);
I dont know if this is the best way but its functionaly :P
selectedValue must euqal (using Equals) with one of the values in the list hence assign the object not the id because the control does not know how to select based on the id
cmbUnidad.SelectedValue = c;
UPDATE: since the Articulos has only the id of unidades and not a reference (which i would have mapped) you have to search for it.
cmbUnidad.SelectedValue = cmbUnidad.Items.Cast<Unidades>().FirstOrDefault(u => u.Nombre == c.id_unidad);

salesforce SOQL : query to fetch all the fields on the entity

I was going through the SOQL documentation , but couldn't find query to fetch all the field data of an entity say , Account , like
select * from Account [ SQL syntax ]
Is there a syntax like the above in SOQL to fetch all the data of account , or the only way is to list all the fields ( though there are lot of fields to be queried )
Create a map like this:
Map<String, Schema.SObjectField> fldObjMap = schema.SObjectType.Account.fields.getMap();
List<Schema.SObjectField> fldObjMapValues = fldObjMap.values();
Then you can iterate through fldObjMapValues to create a SOQL query string:
String theQuery = 'SELECT ';
for(Schema.SObjectField s : fldObjMapValues)
{
String theLabel = s.getDescribe().getLabel(); // Perhaps store this in another map
String theName = s.getDescribe().getName();
String theType = s.getDescribe().getType(); // Perhaps store this in another map
// Continue building your dynamic query string
theQuery += theName + ',';
}
// Trim last comma
theQuery = theQuery.subString(0, theQuery.length() - 1);
// Finalize query string
theQuery += ' FROM Account WHERE ... AND ... LIMIT ...';
// Make your dynamic call
Account[] accounts = Database.query(theQuery);
superfell is correct, there is no way to directly do a SELECT *. However, this little code recipe will work (well, I haven't tested it but I think it looks ok). Understandably Force.com wants a multi-tenant architecture where resources are only provisioned as explicitly needed - not easily by doing SELECT * when usually only a subset of fields are actually needed.
You have to specify the fields, if you want to build something dynamic the describeSObject call returns the metadata about all the fields for an object, so you can build the query from that.
I use the Force.com Explorer and within the schema filter you can click the checkbox next to the TableName and it will select all the fields and insert into your query window - I use this as a shortcut to typeing it all out - just copy and paste from the query window. Hope this helps.
In case anyone was looking for a C# approach, I was able to use reflection and come up with the following:
public IEnumerable<String> GetColumnsFor<T>()
{
return typeof(T).GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance)
.Where(x => !Attribute.IsDefined(x, typeof(System.Xml.Serialization.XmlIgnoreAttribute))) // Exclude the ignored properties
.Where(x => x.DeclaringType != typeof(sObject)) // & Exclude inherited sObject propert(y/ies)
.Where(x => x.PropertyType.Namespace != typeof(Account).Namespace) // & Exclude properties storing references to other objects
.Select(x => x.Name);
}
It appears to work for the objects I've tested (and matches the columns generated by the API test). From there, it's about creating the query:
/* assume: this.server = new sForceService(); */
public IEnumerable<T> QueryAll<T>(params String[] columns)
where T : sObject
{
String soql = String.Format("SELECT {0} FROM {1}",
String.Join(", ", GetColumnsFor<T>()),
typeof(T).Name
);
this.service.QueryOptionsValue = new QueryOptions
{
batchsize = 250,
batchSizeSpecified = true
};
ICollection<T> results = new HashSet<T>();
try
{
Boolean done = false;
QueryResult queryResult = this.service.queryAll(soql);
while (!finished)
{
sObject[] records = queryResult.records;
foreach (sObject record in records)
{
T entity = entity as T;
if (entity != null)
{
results.Add(entity);
}
}
done &= queryResult.done;
if (!done)
{
queryResult = this.service.queryMode(queryResult.queryLocator);
}
}
}
catch (Exception ex)
{
throw; // your exception handling
}
return results;
}
For me it was the first time with Salesforce today and I came up with this in Java:
/**
* #param o any class that extends {#link SObject}, f.ex. Opportunity.class
* #return a list of all the objects of this type
*/
#SuppressWarnings("unchecked")
public <O extends SObject> List<O> getAll(Class<O> o) throws Exception {
// get the objectName; for example "Opportunity"
String objectName= o.getSimpleName();
// this will give us all the possible fields of this type of object
DescribeSObjectResult describeSObject = connection.describeSObject(objectName);
// making the query
String query = "SELECT ";
for (Field field : describeSObject.getFields()) { // add all the fields in the SELECT
query += field.getName() + ',';
}
// trim last comma
query = query.substring(0, query.length() - 1);
query += " FROM " + objectName;
SObject[] records = connection.query(query).getRecords();
List<O> result = new ArrayList<O>();
for (SObject record : records) {
result.add((O) record);
}
return result;
}
I used following to get complete records-
query_all("Select Id, Name From User_Profile__c")
To get complete fields of record, we have to mention those fields as mentioned here-
https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_select.htm
Hope will help you !!!

Is it possible to choose Datagrid grouping order in WPF?

I've just started to learn WPF/C# and I picked a project which would actually be useful to me instead of variations of "Hello, World!" programs.
It's a small app that polls a game server for player information and binds it to a DataGrid. The data is grouped by team, which can be one of four values: Blue, Red, Spectator, or None.
I've got the Linq query working fine, and the DataGrid grouping is almost good, except for one small problem: the order of the four teams groups is different every time. Sometimes Red is first, sometimes None, etc.
Is there any way I can force the groups into the order above?
Here is the Linq query (addr is the server ip):
private void get_server(string addr)
{
var loc = "http://ukcs.gameme.com/api/serverinfo/" + addr + "//players";
XDocument doc = XDocument.Load(#loc);
var server = new ObservableCollection<Player>
(from player in doc.Descendants("player")
orderby player.Element("rank").Value
select new Player
{
name = player.Element("name").Value,
team = player.Element("team").Value,
frags = player.Element("kills").Value + ":" + player.Element("deaths").Value,
rank = int.Parse(player.Element("rank").Value)
});
server.OrderBy(p => p.rank);
ListCollectionView collection = new ListCollectionView(server);
collection.GroupDescriptions.Add(new PropertyGroupDescription("team"));
player_list.ItemsSource = collection;
}
A second problem is that neither of the OrderBys seem to have an effect.
Any help would be appreciated!
To answer your last question first :) The OrderBy's have no meaning here, because after you sort the players, you put the list inside a CollectionView with a grouping which promptly sorts it by Team (since the grouping is on Team).
To get them in the proper order, you can sort them by Team before putting them inside the ListCollectionView. However, this will put them in alphabetical order - and not exactly the order you wanted. You need to implement IComparable and put that in your sort method - i've rewritten your method a bit (I am not so good at that Linq-form - so, bear with me :)):
You made it a bit harder on yourself by introducing a few unnecessary things - I've tried to root them out.
private void get_server(string addr)
{
var loc = "http://ukcs.gameme.com/api/serverinfo/" + addr + "//players";
var doc = XDocument.Load(#loc);
var server = doc.Descendants("player")
.Select(player => new Player
{
name =player.Element("name").Value,
team=player.Element("team").Value,
frags=player.Element("kills").Value +":" +player.Element("deaths").Value,
rank=int.Parse(player.Element("rank").Value)
})
.OrderBy(p => p.team,new CustomSort())
.ThenBy(p => p.rank).ToList();
var collection = new ListCollectionView(server);
collection.GroupDescriptions.Add(new PropertyGroupDescription("team"));
player_list.ItemsSource = collection;
}
public class CustomSort : IComparer<string>
{
public int Compare(string x, string y)
{
if (x.Equals(y))
return 0;
if (y.Equals("None") || x.Equals("Blue"))
return 1;
if (x.Equals("None") || y.Equals("Blue"))
return -1;
if (x.Equals("Red")|| y.Equals("Spectator"))
return -1;
return 1; // y == "Red" and x == "Spectator"
}
}
Hope this helps!

Resources