Salesforce SOQL describe table - salesforce

Is there a way to fetch a list of all fields in a table in Salesforce? DESCRIBE myTable doesn't work, and SELECT * FROM myTable doesn't work.

From within Apex, you can get this by running the following Apex code snippet. If your table/object is named MyObject__c, then this will give you a Set of the API names of all fields on that object that you have access to (this is important --- even as a System Administrator, if certain fields on your table/object are not visible through Field Level Security to you, they will not show up here):
// Get a map of all fields available to you on the MyObject__c table/object
// keyed by the API name of each field
Map<String,Schema.SObjectField> myObjectFields
= MyObject__c.SObjectType.getDescribe().fields.getMap();
// Get a Set of the field names
Set<String> myObjectFieldAPINames = myObjectFields.keyset();
// Print out the names to the debug log
String allFields = 'ALL ACCESSIBLE FIELDS on MyObject__c:\n\n';
for (String s : myObjectFieldAPINames) {
allFields += s + '\n';
}
System.debug(allFields);
To finish this off, and achieve SELECT * FROM MYTABLE functionality, you would need to construct a dynamic SOQL query using these fields:
List<String> fieldsList = new List<String>(myObjectFieldAPINames);
String query = 'SELECT ';
// Add in all but the last field, comma-separated
for (Integer i = 0; i < fieldsList.size()-1; i++) {
query += fieldsList + ',';
}
// Add in the final field
query += fieldsList[fieldsList.size()-1];
// Complete the query
query += ' FROM MyCustomObject__c';
// Perform the query (perform the SELECT *)
List<SObject> results = Database.query(query);

the describeSObject API call returns all the metadata about a given object/table including its fields. Its available in the SOAP, REST & Apex APIs.

Try using Schema.FieldSet
Schema.DescribeSObjectResult d = Account.sObjectType.getDescribe();
Map<String, Schema.FieldSet> FsMap = d.fieldSets.getMap();
complete documentation

Have you tried DESC myTable?
For me it works fine, it's also in the underlying tips in italic. Look:

Related

Dapper, SqlBuilder extension and Order By descending

I am trying to build a simple query that retrieves data in descending order using Dapper. The database is MySql if that's important.
This is the code I used:
var builder = new SqlBuilder();
var sql = #$"SELECT * FROM table t /**orderby**/ LIMIT #paramSkip, #paramTake";
var template = builder.AddTemplate(sql);
builder.OrderBy("#paramOrderBy DESC", parameters: new
{
paramOrderBy = orderBy,
});
// Limit
builder.AddParameters(parameters: new
{
paramSkip = skip,
paramTake = take
});
return Connection.QueryAsync<TableModel>(
template.RawSql, template.Parameters,
transaction: Transaction
);
This always returns data in ascending order. DESC is just ignored. I tried using the DESC keyword in the query or as parameter but the result was the same.
Only thing that worked was putting order parameters and DESC keyword in query itself (by string interpolation)
(Edit: Typos and text simplification)
You need your query to look something like this:
... ORDER BY <Column name> DESC ...
A column name cannot be parameterized, so you need to insert it into the query something like this:
builder.OrderBy($"{orderBy} DESC");
If your orderBy originates from the user in any way, be sure to sanitize it first to prevent SQL injection. You could - for instance - keep a list of valid column names and validate against it.

Can i create a sql table populated with Salesforce objects?

does Salesforce offer a way to obtain all Objects like Account, Contact etc and populate them in a SQL table with certain columns like
ObjectEntity, FieldName , FieldType ?
I'm pretty sure the only way to achieve this would be by using the Schema.sObjectType and Schema.sObjectField. Here is a link to the documentation for getting all sObjects. You will basically call the Schema.getGlobalDescribe() method which will return you a map of sObjectTypes with their sObject name as the key. Then you'll need to call getDesribe() on each sObjectType get the fields of the object from that Describe result. You'll again need to call getDescribe() on each sObjectField in order to have access to the columns you wanted (eg. FieldType). Here is the documentation on that You could save each DescribeFieldResult into a list that goes into a Map of > with the sObject name as the key, then you could do what you want with them... Put them in a table if you like. Keep in mind this is all going to be very expensive when it comes to CPU time. You may even run into some governor limits.
Here is a little example you can run using Execute Anonymous in the developer console where the sObject Name and all its field names and types are printed to the debug logs
Map<String, sObjectType> objects = Schema.getGlobalDescribe();
for(String objName : objects.keySet()){
system.debug('=======' + objName + '=========\n Fields: ');
sObjectType o = objects.get(objName);
DescribeSobjectResult oDRes = o.getDescribe();
Map<String, Schema.SObjectField> fields = dResult.fields.getMap();
for(Schema.SObjectField f : fields.values()){
DescribeFieldResult fDRes = f.getDescribe();
system.debug('name: ' + fDRes.getName() + ' | type: ' + fDRes.getType());
}
}
Hope this helps

How to ignore null or empty values while using find() in Spring MongoRepository

I have a search functionality where there are different parameters and user can choose one or multiple parameters and ignore other parameters.
I want to use findByFirstNameAndLastNameAndAddressAndCountry() for this so that if any parameter is null or empty it can be ignored and the And condition get applied to other parameters
This can be a duplicate issue. You can do it using #Query annotation and your custom Query.
Ref: How to skip #Param in #Query if is null or empty in Spring Data JPA
#Query("select foo from Foo foo where foo.bar = :bar and "
+ "(:goo is null or foo.goo = :goo)")
public List<Foo> findByBarAndOptionalGoo(
#Param("bar") Bar bar,
#Param("goo") Optional<Goo> goo);
Use 'Query' and 'Criteria' option provided by Spring for MongoDB.
Query query = new Query();
if(!obj.getFirstName.isEmpty()){
Criteria criteria1 = Criteria.where('first_name').is(obj.getFirstName);
query.add(criteria1);
}

Dapper with Access, update statement partially not working

I have a product class and tried to evaluate Dapper with Access database.. Select, Delete and Insert operations are working fine, but I have a problem with update operation. It is working in one way only code below)
When I tried to change the Description based on ProductNumber it works (updateStatement2) and Description get updated, but when I tried to change the ProductNumber based on Description (updateStatement1) it doesn't work and ProductNumber doesn't get updated. It bit strange to me. Is it a bug or am I missing anything?. My database is just a basic one and no primary keys set. I have attached a screenshot below
(For more information see my code below)
public class Products
{
public string ProductNumber { get; set; }
public string Description { get; set; }
}
static void Main(string[] args)
{
using (var con = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=test.mdb"))
{
Products product2 = new Products();
product2.ProductNumber = "P2";
product2.Description = "TestProduct2Changed";
var updateStatement2 = #"Update Products Set Description = #Description Where ProductNumber = #ProductNumber";
int outp2 = con.Execute(updateStatement2, product2);
Products product1 = new Products();
product1.ProductNumber = "P3Changed";
product1.Description = "TestProduct3";
var updateStatement1 = #"Update Products Set ProductNumber = #ProductNumber Where Description = #Description";
int outp1 = con.Execute(updateStatement1, product1);
}
}
I am using Dapper version 1.50.2. This is my database screenshot
It looks like ADO Access commands require the parameters to be present in the same order as they appear in the SQL query.
In your original code, for the query that works, the parameters appear in the query string in alphabetical order -
Update Products Set Description = #Description Where ProductNumber = #ProductNumber
This works because the properties are taken from "product2" in alphabetical order. This may not be by design, it might just be the order in which reflection lists them.
In your query that fails, the parameters appear in reverse alphabetical order -
Update Products Set ProductNumber = #ProductNumber Where Description = #Description
.. and this fails because the parameter values get mis-assigned within Access.
You should be able confirm this by changing the order of the parameters in your dynamic parameter alternative. I tried using dynamic parameters and it worked when the parameters were in the same order as which they appeared in the SQL query but failed if they weren't. The database I'm using isn't quite the same as yours but the following should illustrate what I'm talking about:
// Doesn't work (parameter order is incorrect)
con.Execute(
"Update People Set PersonName = #PersonName Where Notes = #Notes",
new { Notes = "NotesChanged", PersonName = "New Name" }
);
// DOES work (parameter order is correct)
con.Execute(
"Update People Set PersonName = #PersonName Where Notes = #Notes",
new { PersonName = "New Name", Notes = "NotesChanged" }
);
While trying to find more information about this, I came across this answer that unfortunately seems to confirm the issue: https://stackoverflow.com/a/11424444/3813189
I guess that it might be possible for the custom SQL generator that you've mentioned in one of your other questions to do some magic to parse the query and retrieve the parameters in the order in which they must appear and to then ensure that they are provided in the correct order.. if someone is maintaining an Access connector for DapperExtensions then it might be worth raising an issue. Because, at the moment, I think that you are correct and that it is an issue with the library.

Accessing new field value generated in SQL via dbContext

I'm using dbContext and I am running a SQL query that is rather complex (just showing a simple example below), so to avoid having to run the query twice to get a count, I am using COUNT AS to return the total number of records as per other advice on this site.
But, I haven't been able to figure out how to access the resulting property:
using (var db = new DMSContext())
{
string queryString = "select *, COUNT(1) OVER() AS TotalRecords FROM DMSMetas";
var Metas = db.DMSMetas.SqlQuery(queryString).ToList();
for (int i = 0; i <= Metas.Count - 1; i++)
{
var Item = Metas[i];
if (i == 0)
{
//Want to do this, but TotalRecords not part of the DMSMeta class. How to access the created column?
Console.WriteLine("Total records found: " + Item.TotalRecords);
}
}
}
In the sample above, the SQL query generates the extra field TotalRecords. When I run the query in Management Studio, the results are as expected. But how do I access the TotalRecords field through dbContext?
I also tried including the TotalRecords field as part of the DMSMeta class, but then the SQL query fails with the error that the TotalRecords field is specified twice. I tried creating a partial class for DMSMeta containing the TotalRecords field, but then the value remains the default value and is not updated during the query.
I also tried the following:
db.Entry(Item).Property("TotalRecords").CurrentValue
But that generated an error too. Any help would be much appreciated - I am sure I am missing something obvious! All I want is to figure out a way to access the total number of records returned by the query
you have to create a new class (not an entity class but a pure DAO class) DMSMetaWithCount (self explanatory ?) and then
context.Database.SqlQuery<DMSMetaWithCount>("select *, COUNT(1) OVER() AS TotalRecords FROM DMSMetas");
please note that
imho, select * is ALWAYS a bad practice.
you will have no tracking on the not entity new class

Resources