According to the Dapper documentation, you can get a dynamic list back from dapper using below code :
var rows = connection.Query("select 1 A, 2 B union all select 3, 4");
((int)rows[0].A)
.IsEqualTo(1);
((int)rows[0].B)
.IsEqualTo(2);
((int)rows[1].A)
.IsEqualTo(3);
((int)rows[1].B)
.IsEqualTo(4);
What is however the use of dynamic if you have to know the field names and datatypes of the fields.
If I have :
var result = Db.Query("Select * from Data.Tables");
I want to be able to do the following :
Get a list of the field names and data types returned.
Iterate over it using the field names and get back data in the following ways :
result.Fields
["Id", "Description"]
result[0].values
[1, "This is the description"]
This would allow me to get
result[0].["Id"].Value
which will give results 1 and be of type e.g. Int 32
result[0].["Id"].Type --- what datattype is the value returned
result[0].["Description"]
which will give results "This is the description" and will be of type string.
I see there is a results[0].table which has a dapperrow object with an array of the fieldnames and there is also a result.values which is an object[2] with the values in it, but it can not be accessed. If I add a watch to the drilled down column name, I can get the id. The automatically created watch is :
(new System.Collections.Generic.Mscorlib_CollectionDebugView<Dapper.SqlMapper.DapperRow>(result as System.Collections.Generic.List<Dapper.SqlMapper.DapperRow>)).Items[0].table.FieldNames[0] "Id" string
So I should be able to get result[0].Items[0].table.FieldNames[0] and get "Id" back.
You can cast each row to an IDictionary<string, object>, which should provide access to the names and the values. We don't explicitly track the types currently - we simply don't have a need to. If that isn't enough, consider using the dapper method that returns an IDataReader - this will provide access to the raw data, while still allowing convenient call / parameterization syntax.
For example:
var rows = ...
foreach(IDictionary<string, object> row in rows) {
Console.WriteLine("row:");
foreach(var pair in row) {
Console.WriteLine(" {0} = {1}", pair.Key, pair.Value);
}
}
Related
I'm trying to combine 3 separate SOQL queries into one, but still end up with 3 separate lists for ease of use and readability later.
List<Object__c> objectList = [SELECT Name, Id, Parent_Object__r.Name, Parent_Object__r.Id,
(SELECT Name, Id FROM Child_Objects__r)
FROM Object__c];
I know I can get a list of child objects thus:
List<Child_Object__c> childObjectList = new List<Child_Object__c>();
for(Object__c object : objectList){
childObjectList.addAll(object.Child_Objects__r);
}
How would I go about adding the Parent_Object__c records to their own list?
I'm assuming a map could be used to deal with duplicates, but how do I get this Parent_Object__c data into that map?
You are basically there.
All lookup fields are available in your example as object.Parent_Object__r. Use a Set to natively avoid duplicates. No deduping required on your part!
Set<Parent_Object__c> parentObjectSet = new Set<Parent_Object__c>();
List<Child_Object__c> childObjectList = new List<Child_Object__c>();
for(Object__c object : objectList){
childObjectList.addAll(object.Child_Objects__r);
parentObjectSet.add(object.Parent_Object__r);
}
Edit:
As per #eyescream (trust him!) you are indeed better off with a map to avoid duplicates.
So the above code would just be slightly different:
Map<Id, Parent_Object__c> parentObjectMap = new Map<Id, Parent_Object__c>();
List<Child_Object__c> childObjectList = new List<Child_Object__c>();
for(Object__c object : objectList){
childObjectList.addAll(object.Child_Objects__r);
if (object.Parent_Object__r != null) {
parentObjectMap.put(object.Parent_Object__r.Id, object.Parent_Object__r);
}
}
Executing below code returns the result that contains the element of type hashmap instead of type T (the basicDBList coming from mongoDB does not have "_class" attribute:
com.mongodb.BasicDBList basicDBList = // output of mongoDB query;
List<T> result = mongoOperations.getConverter().read(List.class, basicDbList);
Is there any way to provide type information of List to the read method ?
Not exactly clear what you're trying to achieve, but if you acquired your BasicDBList by calling the getRawResults().get("result") of an AggregationResults instance, you can instead call getMappedResults:
Aggregation aggregation = Aggregation.newAggregation(...);
AggregationResults<Foo> r = mongoTemplate.aggregate(aggregation, "foos", Foo.class);
List<Foo> foos = r.getMappedResults();
I have a solution that works for what I want, but I'm hoping to get some slick LINQ types to help me improve what I have, and learn something new in the process.
The code below is used verify that certain column names exist on a spreadsheet. I was torn between using column index values or column names to find them. They both have good and bad points, but decided to go with column names. They'll always exist, and sometimes in different order, though I'm working on this.
Details:
GetData() method returns a DataTable from the Excel spreadsheet. I cycle through all the required field names from my array, looking to see if it matches with something in the column collection on the spreadsheet. If not, then I append the missing column name to an output parameter from the method. I need both the boolean value and the missing fields variable, and I wasn't sure of a better way than using the output parameter. I then remove the last comma from the appended string for the display on the UI. If the StringBuilder object isn't null (I could have used the missingFieldCounter too) then I know there's at least one missing field, bool will be false. Otherwise, I just return output param as empty, and method as true.
So, Is there a more slick, all-in-one way to check if fields are missing, and somehow report on them?
private bool ValidateFile(out string errorFields)
{
data = GetData();
List<string> requiredNames = new [] { "Site AB#", "Site#", "Site Name", "Address", "City", "St", "Zip" }.ToList();
StringBuilder missingFields = null;
var missingFieldCounter = 0;
foreach (var name in requiredNames)
{
var foundColumn = from DataColumn c in data.Columns
where c.ColumnName == name
select c;
if (!foundColumn.Any())
{
if (missingFields == null)
missingFields = new StringBuilder();
missingFieldCounter++;
missingFields.Append(name + ",");
}
}
if (missingFields != null)
{
errorFields = missingFields.ToString().Substring(0, (missingFields.ToString().Length - 1));
return false;
}
errorFields = string.Empty;
return true;
}
Here is the linq solution that makes the same.
I call the ToArray() function to activate the linq statement
(from col in requiredNames.Except(
from dataCol in data
select dataCol.ColumnName
)
select missingFields.Append(col + ", ")
).ToArray();
errorFields = missingFields.ToString();
Console.WriteLine(errorFields);
I have just 2 objects and simple query to retrieve the data.
The result of query which is stored in array ccList according to debug output is:
(
CustomThree__c:
{
Name=cusmei3 2,
customOne__c=a005000000IwnOPAAZ,
Id=a025000000FsFGQAA3
},
CustomThree__c:
{
Name=cusmei3 1,
customOne__c=a005000000IwnOUAAZ,
Id=a025000000FsFGLAA3
}
)
As you can see system.debug(ccList[0]) returns:
CustomThree__c:{
Name=cusmei3 2,
customOne__c=a005000000IwnOPAAZ,
Id=a025000000FsFGQAA3
}
But when I try to get Id (or other field) from the array, the error occurs.
Can anyone point out what am I doing wrong?
code
Object[] ccList;
ccList = [SELECT id, name, CustomOne__r.name FROM CustomThree__c];
system.debug(ccList);
system.debug('******************************************');
system.debug(ccList[0]);
system.debug(ccList[0].Id); //this one cause the error
I think you'll have to change the type of ccList from "Object" to "CustomThree__c". This will also give you compile-time checking when you'll try to write ccList[0].SomeNonExistentFieldName__c.
If you can't do it and really need the object that stores result to be generic - I believe this should be SObject?
I'm trying to figure out how to execute a custom query with Castle ActiveRecord.
I was able to run simple query that returns my entity, but what I really need is the query like that below (with custom field set):
select count(1) as cnt, data from workstationevent where serverdatetime >= :minDate and serverdatetime < :maxDate and userId = 1 group by data having count(1) > :threshold
Thanks!
In this case what you want is HqlBasedQuery. Your query will be a projection, so what you'll get back will be an ArrayList of tuples containing the results (the content of each element of the ArrayList will depend on the query, but for more than one value will be object[]).
HqlBasedQuery query = new HqlBasedQuery(typeof(WorkStationEvent),
"select count(1) as cnt, data from workstationevent where
serverdatetime >= :minDate and serverdatetime < :maxDate
and userId = 1 group by data having count(1) > :threshold");
var results =
(ArrayList)ActiveRecordMediator.ExecuteQuery(query);
foreach(object[] tuple in results)
{
int count = (int)tuple[0]; // = cnt
string data = (string)tuple[1]; // = data (assuming this is a string)
// do something here with these results
}
You can create an anonymous type to hold the results in a more meaningful fashion. For example:
var results = from summary in
(ArrayList)ActiveRecordMediator.ExecuteQuery(query)
select new {
Count = (int)summary[0], Data = (string)summary[1]
};
Now results will contain a collection of anonymous types with properties Count and Data. Or indeed you could create your own summary type and populate it out this way too.
ActiveRecord also has the ProjectionQuery which does much the same thing but can only return actual mapped properties rather than aggregates or functions as you can with HQL.
Be aware though, if you're using ActiveRecord 1.0.3 (RC3) as I was, this will result in a runtime InvalidCastException. ActiveRecordMediator.ExecuteQuery returns an ArrayList and not a generic ICollection. So in order to make it work, just change this line:
var results = (ICollection<object[]>) ActiveRecordMediator.ExecuteQuery(query);
to
var results = (ArrayList) ActiveRecordMediator.ExecuteQuery(query);
and it should work.
Also note that using count(1) in your hql statement will make the query return an ArrayList of String instead of an ArrayList of object[] (which is what you get when using count(*).)
Just thought I'd point this out for the sake of having it all documented in one place.