I'm pretty new to writing Apex but everything does seem to be running smoothly separately in an executable window when I split apart the class I created below, but when I'm running this from within a flow it doesn't seem to create the records at all. The methods that delete records seem to be working, but neither of the methods to create the records is working it seems.
Any help or guidance is much appreciated!
public without sharing class CreateQuoteProducts_NewOrRenewal{
#invocableMethod
public static void DeleteQuoteProductsMRF(List<Id> OrderId){
List<Quote_Product_MRF__c> QuoteProductsMRF = [SELECT id from Quote_Product_MRF__c WHERE Order__c in : OrderId];
if(!QuoteProductsMRF.isEmpty()){
delete QuoteProductsMRF;
}
}
public static void DeleteQuoteProductsOTF(List<Id> OrderId){
List<Quote_Product__c> QuoteProductsOTF = [SELECT id from Quote_Product__c WHERE Order__c in : OrderId];
if(!QuoteProductsOTF.isEmpty()){
delete QuoteProductsOTF;
}
}
/* ---START--- Create Quote Products MRF ---START--- */
public static void CreateQuoteProductsMRF(List<Id> OrderId){
List<AggregateResult> nrqpmrfOP = [
SELECT
count(Id) ct,
Order__c ord,
sum(Total_Monthly_Recurring_Fees__c) stmr,
sum(Monthly_Recurring_Fees__c) mr,
sum(Discount_MRF__c) dmr
FROM Order_Location_Package__c
WHERE Order__c in : OrderId AND Package__r.Monthly_Recurring_Price__c != null
GROUP BY Package__c, Order__c];
List<Quote_Product_MRF__c> nrqpmrf = New List<Quote_Product_MRF__c>();
for(AggregateResult ar : nrqpmrfOP){
Quote_Product_MRF__c QuoteProductMRF = New Quote_Product_MRF__c();
QuoteProductMRF.Quantity__c = (Decimal)ar.get('ct');
QuoteProductMRF.Order__c = (String)ar.get('ord');
QuoteProductMRF.Total_Monthly_Recurring_Fees__c = (Decimal)ar.get('stmr');
QuoteProductMRF.Monthly_Recurring_Fees__c = (Decimal)ar.get('mr');
QuoteProductMRF.Discount_MRF__c = (Decimal)ar.get('dmr');
QuoteProductMRF.Product_Type__c = 'Package';
nrqpmrf.add(QuoteProductMRF);
}
Insert nrqpmrf;
}
/* ---END--- Create Quote Products MRF ---END--- */
/* ---START--- Create Quote Products OTF ---START--- */
public static void CreateQuoteProductsOTF(List<Id> OrderId){
List<AggregateResult> nrqpmrfOP = [
SELECT
count(Id) ct,
Order__c ord,
sum(Total_One_Time_Fees__c) stmr,
sum(One_Time_Fees__c) mr,
sum(Discount_OTF__c) dmr
FROM Order_Location_Package__c
WHERE Order__c in : OrderId AND Package__r.One_Time_Price__c != null
GROUP BY Package__c, Order__c];
List<Quote_Product__c> nrqpotf = New List<Quote_Product__c>();
for(AggregateResult ar : nrqpmrfOP){
Quote_Product__c QuoteProductOTF = New Quote_Product__c();
QuoteProductOTF.Quantity__c = (Decimal)ar.get('ct');
QuoteProductOTF.Order__c = (String)ar.get('ord');
QuoteProductOTF.Total_One_Time_Fees__c = (Decimal)ar.get('stmr');
QuoteProductOTF.One_Time_Fees__c = (Decimal)ar.get('mr');
QuoteProductOTF.Discount_OTF__c = (Decimal)ar.get('dmr');
QuoteProductOTF.Product_Type__c = 'Package';
nrqpotf.add(QuoteProductOTF);
}
Insert nrqpotf;
}
/* ---END--- Create Quote Products ORD ---END--- */
}
Test Class Below
#isTest
private class CreateQuoteProducts_NewOrRenewalTest {
private static testMethod void doTest() {
Account testAcc = new Account ();
testAcc.Name = 'Test Account';
testAcc.Primary_Vertical__c = 'Multifamily Housing';
testAcc.Total_Locations_Owned_Managed__c = 1;
insert testAcc;
Opportunity testOpp = new Opportunity ();
testOpp.Name = 'Test Opportunity';
testOpp.AccountId = testAcc.Id;
testOpp.Opportunity_Source__c = 'Sales Generated';
testOpp.Type = 'New';
testOpp.StageName = 'Contract';
testOpp.Number_of_locations_for_opportunity__c = 1;
testOpp.Amount = 0;
testOpp.Implementation__c = 0;
testOpp.CloseDate = System.today() + 5;
testOpp.Deal_Confidence__c = 100;
insert testOpp;
Package__c testPackage = new Package__c ();
testPackage.Name = 'Test Package';
testPackage.Package_Type__c = 'Website Package';
testPackage.Status__c = 'Active';
testPackage.One_Time_Price__c = String.ValueOf(200);
testPackage.Monthly_Recurring_Price__c = String.ValueOf(100);
insert testPackage;
Order_Sheet__c testOrder = new Order_Sheet__c ();
testOrder.Opportunity__c = testOpp.id;
insert testOrder;
Order_New_Location__c testOrderLocation = new Order_New_Location__c ();
testOrderLocation.Order_Sheet__c = testOrder.id;
testOrderLocation.Name = 'Test Location';
insert testOrderLocation;
Order_Location_Package__c testOrderPackage = new Order_Location_Package__c ();
testOrderPackage.Order__c = testOrder.Id;
testOrderPackage.New_Location_Name__c = testOrderLocation.Id;
testOrderPackage.Package__c = testPackage.Id;
insert testOrderPackage;
/* --- Delete Quote Product MRF Test --- */
Test.startTest();
/* --- Create Quote Product MRF--- */
Quote_Product_MRF__c testQPMRF = new Quote_Product_MRF__c ();
testQPMRF.Order__c = testOrder.id;
insert testQPMRF;
/* --- Run Delete Method--- */
CreateQuoteProducts_NewOrRenewal.DeleteQuoteProductsMRF(new List<Id>{testOrder.id});
/* --- Query for QP OTF--- */
list<Quote_Product_MRF__c>queriedQPMRF = [Select Id FROM Quote_Product_MRF__c WHERE Order__c = :testOrder.id];
/* --- Checks for 0 records --- */
system.assertEquals(0, queriedQPMRF.size());
/* --- Delete Quote Product OTF Test --- */
/* --- Create Quote Product OTF--- */
Quote_Product__c testQPOTF = new Quote_Product__c ();
testQPOTF.Order__c = testOrder.id;
insert testQPOTF;
/* --- Run Delete Method--- */
CreateQuoteProducts_NewOrRenewal.DeleteQuoteProductsOTF(new List<Id>{testOrder.id});
/* --- Query for QP OTF--- */
list<Quote_Product__c>queriedQPOTF = [Select Id FROM Quote_Product__c WHERE Order__c = :testOrder.id];
/* --- Checks for 0 records --- */
system.assertEquals(0, queriedQPOTF.size());
/* --- Create Quote Product MRF Test --- */
/* --- Run Create Method--- */
CreateQuoteProducts_NewOrRenewal.CreateQuoteProductsMRF(new List<Id>{testOrder.id});
/* --- Query for QP OTF--- */
list<Quote_Product_MRF__c>queriedQPMRFCreated = [Select Id FROM Quote_Product_MRF__c WHERE Order__c = :testOrder.id];
/* --- Checks for 1 record --- */
system.assertEquals(1, queriedQPMRFCreated.size());
/* --- Create Quote Product OTF Test --- */
/* --- Run Create Method--- */
CreateQuoteProducts_NewOrRenewal.CreateQuoteProductsOTF(new List<Id>{testOrder.id});
/* --- Query for QP OTF--- */
list<Quote_Product__c>queriedQPOTFCreated = [Select Id FROM Quote_Product__c WHERE Order__c = :testOrder.id];
/* --- Checks for 1 record --- */
system.assertEquals(1, queriedQPOTFCreated.size());
Test.stopTest();
}
}
As mentioned above, if I run the below apex in an executable window and replace the ID with and actual Order Id, it does successfully create the records, just not when I run the full class from flow.
List<AggregateResult> nrqpmrfOP = [
SELECT
count(Id) ct,
Order__c ord,
sum(Total_Monthly_Recurring_Fees__c) stmr,
sum(Monthly_Recurring_Fees__c) mr,
sum(Discount_MRF__c) dmr
FROM Order_Location_Package__c
WHERE Order__c in : OrderId AND Package__r.Monthly_Recurring_Price__c != null
GROUP BY Package__c, Order__c];
List<Quote_Product_MRF__c> nrqpmrf = New List<Quote_Product_MRF__c>();
for(AggregateResult ar : nrqpmrfOP){
Quote_Product_MRF__c QuoteProductMRF = New Quote_Product_MRF__c();
QuoteProductMRF.Quantity__c = (Decimal)ar.get('ct');
QuoteProductMRF.Order__c = (String)ar.get('ord');
QuoteProductMRF.Total_Monthly_Recurring_Fees__c = (Decimal)ar.get('stmr');
QuoteProductMRF.Monthly_Recurring_Fees__c = (Decimal)ar.get('mr');
QuoteProductMRF.Discount_MRF__c = (Decimal)ar.get('dmr');
QuoteProductMRF.Product_Type__c = 'Package';
nrqpmrf.add(QuoteProductMRF);
}
Insert nrqpmrf;
As specified in documentation (developer.salesforce.com/docs/atlas.en-us.apexcode.meta/…), there can be only 1 InvocableMethod by class. This means that your flow only call the first delete method, not the others. If you need to call each method, then you need to do a class for each. Maybe a screenshot of the flow might help. – Bartheleway
Related
I need to create a new expense card, the input parameters are Amount, Date and Description.
Fields that must be filled in the expense card to create it:
Card keeper is contact
Months Expenses Applications is a custom object
When creating an expense card, if Months Expenses Applications exists by the date entered in the "Date" field, then a new expense card is created from which Months Expenses Applications is taken from the existing one
if, by the date entered in the "date" field, there is no Months Expenses Applications, you need to create Months Expenses Applications and then create an expense map in which Months Expenses Applications will have a new Months Expenses Applications created
I tried to create an expense map with "Amount" "Date" "Description" equal to the input parameters, but I don't know how to specify MonthExpenseApplication__c
public static void createNewExpenseCard(Integer amount, Date createdDate, String description) {
Month_Expense_Application__c MonthApplication = [
SELECT Name, MonthDate__c
FROM Month_Expense_Application__c
WHERE MonthDate__c =: createdDate
];
if (MonthApplication != null) {
ExpenseCard__c exp = new ExpenseCard__c(
Amount__c = amount,
CardDate__c = createdDate,
Description__c = description,
CardKeeper__c = '0034x00001K7kGCAAZ'
);
exp.MonthExpenseApplication__c = [
SELECT MonthExpenseApplication__c
FROM ExpenseCard__c
WHERE MonthExpenseApplication__c =: MonthApplication.Id
].Id;
insert exp;
} else {
Month_Expense_Application__c monthApp = new Month_Expense_Application__c(
Balance__c = 1000,
MonthDate__c = createdDate,
Keeper__c = '0034x00001K7kGCAAZ'
);
ExpenseCard__c exp2 = new ExpenseCard__c(
Amount__c = amount,
CardDate__c = createdDate,
Description__c = description,
CardKeeper__c = '0034x00001K7kGCAAZ'
);
insert exp2;
}
}
This is dangerous:
Month_Expense_Application__c MonthApplication = [
SELECT Name, MonthDate__c
FROM Month_Expense_Application__c
WHERE MonthDate__c =: createdDate
];
If there are zero results it will throw "list has no rows for assignment". Similar if there's more than 1.
Something like this?
Integer amount = 50;
Date createdDate = System.today();
String description = 'Lorem ipsum...';
Month_Expense_Application__c app;
List<Month_Expense_Application__c> applications = [SELECT Id
FROM Month_Expense_Application__c
WHERE MonthDate__c =: createdDate
LIMIT 1];
if(applications.isEmpty()){
app = new Month_Expense_Application__c(
Balance__c = 1000,
MonthDate__c = createdDate,
Keeper__c = '0034x00001K7kGCAAZ'
);
insert app;
} else {
app = applications[0];
}
// one way or another - the monthly allowance exists now. So just use its id in the lookup
ExpenseCard__c exp = new ExpenseCard__c(
Amount__c = amount,
CardDate__c = createdDate,
Description__c = description,
CardKeeper__c = '0034x00001K7kGCAAZ',
Month_Expense_Application__c = app.Id
);
There are more elegant ways to do it, you'd need to read up about upsert and external ids - but it should be good enough.
I keep getting the following error when I write a test class for opportunity line items.
System.DmlException: Insert failed. First exception on row 0; first error: FIELD_INTEGRITY_EXCEPTION, field integrity exception: PricebookEntryId (pricebook entry is in a different pricebook than the one assigned to the opportunity): [PricebookEntryId]
Here is my code.
#isTest
public class PreventLineItemDeletionTestClass {
static testmethod void PreventLineItemDeletionTestClass(){
Id pricebookId = Test.getStandardPricebookId();
// insert product
Product2 p = new Product2();
p.Name = ' Test Product ';
p.Description='Test Product Entry For Product';
p.productCode = 'SFDCPanther-123';
p.isActive = true;
insert p;
// insert pricebook entry for the product
PricebookEntry pbEntry = new PricebookEntry(
Pricebook2Id = pricebookId ,
Product2Id = p.Id,
UnitPrice = 100.00,
IsActive = true);
insert pbEntry;
// Create Opportunity
Opportunity opp = new Opportunity();
opp.Name = 'Opp for Test Account New';
opp.CloseDate= System.Today();
opp.StageName='Negotiation';
opp.Pricebook2Id = pricebookId;
insert opp;
system.debug('opp.pricebook2Id!!!!'+opp.pricebook2Id+'pbEntry.Pricebook2Id !!!'+pbEntry.Pricebook2Id);
// Add product and Pricebook to the particular opportunity using OpportunityLineItem
OpportunityLineItem ol = new OpportunityLineItem();
ol.opportunityid = opp.id;
ol.quantity = 4;
ol.TotalPrice = ol.quantity * pbEntry.UnitPrice ;
ol.Product2Id = p.id;
ol.PricebookEntryId = pbEntry.Id;
ol.Fulfillment__c = 2;
insert ol;
}
}
Could someone please let me know what I am doing wrong.
Best,
Mike
Screenshot from Eclipse.
I'm trying to read from my ResultSet variable an attribute which is an array of dates Date [], but I can't do it with any of the available functions. Could anyone kindly help me? Thank you.
a ResultSet function that reads an array of Dates does not exist, so since I had a daterange [] in postgresql, I replaced it with LocalDate []. I found a file on GitHub that implements the range, but the import doesn't work for me.
public static ArrayList<Parlamentare> elenco_Parlamentari()throws
NullPointerException{
String url = "jdbc:postgresql://localhost/Parlamento"; //cambia mydb
String user = "postgres";
String password = "";
ArrayList<Parlamentare> elenco = new ArrayList<Parlamentare>();
Range r;
Statement st;
ResultSet rs;
String sql;
try(Connection cn = DriverManager.getConnection(url, user, password);)
{
if(cn != null) {
System.out.println("Connected to PostgreSQL server
successfully!");
}else {
System.out.println("Failed to connect PostgreSQL server");
}
sql = "SELECT
nome,partito,circoscrizione,data_nascita,luogo,titolo_studi,
mandati,commissioni,periodo_carica FROM parlamentari;";
st = cn.createStatement(); // creo sempre uno statement sulla
// connessione
String nome = "";
String partito = "";
String circoscrizione = "";
Date data_nascita = null;
String luogo = null;
String titolo_studi = "";
String[] mandati = null;
String[] commissioni = null;
LocalDate[] periodo_carica = null;
// LocalDate localDate = null;
rs = st.executeQuery(sql); // faccio la query su uno statement
while (rs.next() == true) {
try {
Parlamentare a=new Parlamentare();
nome = rs.getString("nome");
partito = rs.getString("partito");
circoscrizione = rs.getString("circoscrizione");
data_nascita = rs.getDate("data_nascita");
luogo = rs.getString("luogo");
titolo_studi = rs.getString("titolo_studi");
if(rs.getArray("mandati") == null)
mandati=null;
else mandati=rs.getArray("mandati").toString().split(",");
if(rs.getArray("commissioni") == null)
commissioni=null;
else
commissioni=rs.getArray("commissioni").toString().split(",");
rs.getObject("periodo_carica").getClass();
// LocalDate localDate =
rs.getObject(1, LocalDate.class);
// case "daterange":
// return Range.localDateRange(value);
rs.getType()==
if(rs.getArray("periodo_carica") == null)
periodo_carica = null;
else periodo_carica =
rs.getObject("periodo_carica").getClass();
//rs.getArray("periodo_carica").toString();
// getDate();
// getObject("periodo_carica").;
/// toString().;// toString().split(",");
// .getDate("periodo_carica");//.toString().split(",");
System.out.print("rs.getObject(\"periodo_carica\").getClass()="+
rs.getObject("periodo_carica").getClass());
//rs.getObject(...).getClass()
a = new
Parlamentare(nome,partito,circoscrizione,data_nascita,
luogo,titolo_studi,
mandati,commissioni,periodo_carica);
elenco.add(a);
}
catch(NullPointerException obj) {
obj.printStackTrace();
}
}
cn.close(); // chiusura connessione
} catch (SQLException e) {
System.out.println("errore:" + e.getMessage());
e.printStackTrace();
}
return elenco;
} //end elenco_Parlamentari()
in postgresql:
CREATE TABLE public.parlamentari (
nome character varying(100) COLLATE pg_catalog."default" NOT NULL,
partito character varying(100) COLLATE pg_catalog."default" NOT NULL,
circoscrizione character varying(100) COLLATE pg_catalog."default"
NOT NULL,
data_nascita date,
luogo character varying(100) COLLATE pg_catalog."default",
titolo_studi character varying(100) COLLATE pg_catalog."default",
mandati character varying(1000)[] COLLATE pg_catalog."default",
commissioni character varying(100)[] COLLATE pg_catalog."default",
periodo_carica daterange[],
CONSTRAINT parlamentari_pkey PRIMARY KEY (nome, partito,
circoscrizione),
CONSTRAINT parlamentarinomekey UNIQUE (nome),
CONSTRAINT parlamentaripartitonomekey UNIQUE (partito, nome)
)
TABLESPACE pg_default;
ALTER TABLE public.parlamentari
OWNER to postgres;
GRANT ALL ON TABLE public.parlamentari TO postgres;
GRANT ALL ON TABLE public.parlamentari TO PUBLIC;
Parlamentare.java
public Parlamentare() {
String nome = "";
String partito = "";
String circoscrizione = "";
Date data_nascita = null;
String luogo = null;
String titolo_studi = "";
String[] mandati = null;
String[] commissioni = null;
LocalDate[] periodo_carica = null;
}
Sample Query Output
In the event you can't make your JDBC library work with the daterange type from PG, perhaps you can re-write the query to convert the daterange DB objs into strings (so an ARRAY but of type string) OR just a combined string - see pg array_to_string fn - in which case you process the resultant string in Java land.
I am a newbie at programming so please bear with me (I am taking an online course).
I am at a point in the lesson where we were supposed to create a database in a java class and a table called "pets" would get created in the onCreate method of the main activity (called CatalogActivity).
At this point, I have already downloaded the app exactly in the form it is supposed to be (to make sure I haven't made a mistake before in my code), but when I run the app on the emulator, no table gets created.
The idea is, when I run the app, the database called shelter.db should get created and in it, the table called "pets". This table is defined in the PetDbHelper.java class.
When searching in Android Studio terminal, I see no tables in shelter.db. So I downloaded shelter.db to my PC and opened it with SQL browser - still no "pets" table. Looks like for some reason, the table doesn't get created :(
I don't know why as I seem to be following all the instructions to the point.
Does anyone have advice how to fix this, please?
Here is a link to the code: https://github.com/soralka/PetsApp_error
Thanks in advance!
Soralka
Here's the LOG when I use the CommonSQLiteUtilities class:
07-18 19:37:44.344 15867-15867/? I/le.android.pet: Not late-enabling -Xcheck:jni (already on)
07-18 19:37:44.416 15867-15867/? W/le.android.pet: Unexpected CPU variant for X86 using defaults: x86
07-18 19:37:44.662 15867-15867/com.example.android.pets I/le.android.pet: The ClassLoaderContext is a special shared library.
07-18 19:37:45.027 15867-15867/com.example.android.pets W/le.android.pet: JIT profile information will not be recorded: profile file does not exits.
07-18 19:37:45.051 15867-15867/com.example.android.pets I/chatty: uid=10083(com.example.android.pets) identical 10 lines
07-18 19:37:45.051 15867-15867/com.example.android.pets W/le.android.pet: JIT profile information will not be recorded: profile file does not exits.
07-18 19:37:45.137 15867-15867/com.example.android.pets I/InstantRun: starting instant run server: is main process
07-18 19:37:45.840 15867-15867/com.example.android.pets W/le.android.pet: Accessing hidden method Landroid/view/View;->computeFitSystemWindows(Landroid/graphics/Rect;Landroid/graphics/Rect;)Z (light greylist, reflection)
07-18 19:37:45.850 15867-15867/com.example.android.pets W/le.android.pet: Accessing hidden method Landroid/view/ViewGroup;->makeOptionalFitsSystemWindows()V (light greylist, reflection)
07-18 19:37:46.066 15867-15867/com.example.android.pets D/SQLITE_CSU: DatabaseList Row 1 Name=main File=/data/user/0/com.example.android.pets/databases/shelter.db
07-18 19:37:46.068 15867-15867/com.example.android.pets D/SQLITE_CSU: Database Version = 1
07-18 19:37:46.071 15867-15867/com.example.android.pets D/SQLITE_CSU: Table Name = android_metadata Created Using = CREATE TABLE android_metadata (locale TEXT)
07-18 19:37:46.073 15867-15867/com.example.android.pets D/SQLITE_CSU: Table = android_metadata ColumnName = locale ColumnType = TEXT Default Value = null PRIMARY KEY SEQUENCE = 0
07-18 19:37:46.074 15867-15867/com.example.android.pets D/SQLITE_CSU: Table Name = pets Created Using = CREATE TABLE pets (_id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, breed TEXT, gender INTEGER NOT NULL, weight INTEGER NOT NULL DEFAULT 0)
07-18 19:37:46.077 15867-15867/com.example.android.pets D/SQLITE_CSU: Table = pets ColumnName = _id ColumnType = INTEGER Default Value = null PRIMARY KEY SEQUENCE = 1
07-18 19:37:46.078 15867-15867/com.example.android.pets D/SQLITE_CSU: Table = pets ColumnName = name ColumnType = TEXT Default Value = null PRIMARY KEY SEQUENCE = 0
07-18 19:37:46.079 15867-15867/com.example.android.pets D/SQLITE_CSU: Table = pets ColumnName = breed ColumnType = TEXT Default Value = null PRIMARY KEY SEQUENCE = 0
Table = pets ColumnName = gender ColumnType = INTEGER Default Value = null PRIMARY KEY SEQUENCE = 0
Table = pets ColumnName = weight ColumnType = INTEGER Default Value = 0 PRIMARY KEY SEQUENCE = 0
07-18 19:37:46.080 15867-15867/com.example.android.pets D/SQLITE_CSU: Table Name = sqlite_sequence Created Using = CREATE TABLE sqlite_sequence(name,seq)
07-18 19:37:46.082 15867-15867/com.example.android.pets D/SQLITE_CSU: Table = sqlite_sequence ColumnName = name ColumnType = Default Value = null PRIMARY KEY SEQUENCE = 0
Table = sqlite_sequence ColumnName = seq ColumnType = Default Value = null PRIMARY KEY SEQUENCE = 0
07-18 19:37:46.134 15867-15867/com.example.android.pets D/OpenGLRenderer: Skia GL Pipeline
07-18 19:37:46.260 15867-15886/com.example.android.pets I/ConfigStore: android::hardware::configstore::V1_0::ISurfaceFlingerConfigs::hasWideColorDisplay retrieved: 0
07-18 19:37:46.262 15867-15886/com.example.android.pets I/ConfigStore: android::hardware::configstore::V1_0::ISurfaceFlingerConfigs::hasHDRDisplay retrieved: 0
07-18 19:37:46.262 15867-15886/com.example.android.pets I/OpenGLRenderer: Initialized EGL, version 1.4
07-18 19:37:46.262 15867-15886/com.example.android.pets D/OpenGLRenderer: Swap behavior 1
07-18 19:37:46.262 15867-15886/com.example.android.pets W/OpenGLRenderer: Failed to choose config with EGL_SWAP_BEHAVIOR_PRESERVED, retrying without...
07-18 19:37:46.263 15867-15886/com.example.android.pets D/OpenGLRenderer: Swap behavior 0
07-18 19:37:46.284 15867-15886/com.example.android.pets D/EGL_emulation: eglCreateContext: 0xe4fbebc0: maj 3 min 0 rcv 3
07-18 19:37:46.347 15867-15886/com.example.android.pets D/EGL_emulation: eglMakeCurrent: 0xe4fbebc0: ver 3 0 (tinfo 0xe79c7930)
07-18 19:37:46.534 15867-15886/com.example.android.pets D/EGL_emulation: eglMakeCurrent: 0xe4fbebc0: ver 3 0 (tinfo 0xe79c7930)
Based upon your code I can see no issues.
You may wish to try deleting the App's data, or uninstalling the App adding the line below (or adding the CommonSQLiteUtilities class and adding the two lines that have been added for testing below) and then rerunning the App (this would overcome any issue you may have had that resulted in the database being created but not any tables, in which case the onCreate method would not run so any corrective changes (if any) may not have been applied).
Amending the CatalogActivity by adding the line :-
displayDatabaseInfo();
Results in the EditText being updated as expected (shows 0 rows in pets database).
If the underlying table didn't exist then if you added the line above, you'd experience an exception along the lines of :-
07-17 01:28:51.001 1321-1321/pets.pets E/AndroidRuntime: FATAL EXCEPTION: main
java.lang.RuntimeException: Unable to start activity ComponentInfo{pets.pets/pets.pets.CatalogActivity}: android.database.sqlite.SQLiteException: no such table: notatable (code 1): , while compiling: SELECT * FROM notatable
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2059)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2084)
at android.app.ActivityThread.access$600(ActivityThread.java:130)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4745)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native Method)
Caused by: android.database.sqlite.SQLiteException: no such table: notatable (code 1): , while compiling: SELECT * FROM notatable
at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)
at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:882)
at android.database.sqlite.SQLiteConnection.prepare(SQLiteConnection.java:493)
at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:588)
at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:58)
at android.database.sqlite.SQLiteQuery.<init>(SQLiteQuery.java:37)
at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:44)
at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1314)
at android.database.sqlite.SQLiteDatabase.rawQuery(SQLiteDatabase.java:1253)
at pets.pets.CatalogActivity.displayDatabaseInfo(CatalogActivity.java:40)
at pets.pets.CatalogActivity.onCreate(CatalogActivity.java:22)
at android.app.Activity.performCreate(Activity.java:5008)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1079)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2023)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2084)
at android.app.ActivityThread.access$600(ActivityThread.java:130)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4745)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native Method)
Note forced by changing the table name to notatable i.e.
Cursor cursor = db.rawQuery("SELECT * FROM " + "notatable", null);
Adding the CommonSQLiteUtilities class from Are there any methods that assist with resolving common SQLite issues?
and then adding the line :-
CommonSQLiteUtilities.logDatabaseInfo(mDbHelper.getWritableDatabase());
results in the log containing :-
07-17 01:36:51.191 1399-1399/? D/SQLITE_CSU: DatabaseList Row 1 Name=main File=/data/data/pets.pets/databases/shelter.db
Database Version = 1
Table Name = android_metadata Created Using = CREATE TABLE android_metadata (locale TEXT)
Table = android_metadata ColumnName = locale ColumnType = TEXT Default Value = null PRIMARY KEY SEQUENCE = 0
Table Name = pets Created Using = CREATE TABLE pets (_id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, breed TEXT, gender INTEGER NOT NULL, weight INTEGER NOT NULL DEFAULT 0)
Table = pets ColumnName = _id ColumnType = INTEGER Default Value = null PRIMARY KEY SEQUENCE = 1
Table = pets ColumnName = name ColumnType = TEXT Default Value = null PRIMARY KEY SEQUENCE = 0
Table = pets ColumnName = breed ColumnType = TEXT Default Value = null PRIMARY KEY SEQUENCE = 0
Table = pets ColumnName = gender ColumnType = INTEGER Default Value = null PRIMARY KEY SEQUENCE = 0
Table = pets ColumnName = weight ColumnType = INTEGER Default Value = 0 PRIMARY KEY SEQUENCE = 0
Table Name = sqlite_sequence Created Using = CREATE TABLE sqlite_sequence(name,seq)
Table = sqlite_sequence ColumnName = name ColumnType = Default Value = null PRIMARY KEY SEQUENCE = 0
Table = sqlite_sequence ColumnName = seq ColumnType = Default Value = null PRIMARY KEY SEQUENCE = 0
Further confirming that the table is created.
The testing above was done using the following code :-
CatalogActivity.java
public class CatalogActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_catalog);
//displayDatabaseInfo();
PetDbHelper mDbHelper = new PetDbHelper(this);
SQLiteDatabase db = mDbHelper.getReadableDatabase();
displayDatabaseInfo();
CommonSQLiteUtilities.logDatabaseInfo(mDbHelper.getWritableDatabase());
}
/**
* Temporary helper method to display information in the onscreen TextView about the state of
* the pets database.
*/
private void displayDatabaseInfo() {
// To access our database, we instantiate our subclass of SQLiteOpenHelper
// and pass the context, which is the current activity.
PetDbHelper mDbHelper = new PetDbHelper(this);
// Create and/or open a database to read from it
SQLiteDatabase db = mDbHelper.getReadableDatabase();
// Perform this raw SQL query "SELECT * FROM pets"
// to get a Cursor that contains all rows from the pets table.
Cursor cursor = db.rawQuery("SELECT * FROM " + PetContract.PetEntry.TABLE_NAME, null);
try {
// Display the number of rows in the Cursor (which reflects the number of rows in the
// pets table in the database).
TextView displayView = (TextView) findViewById(R.id.text_view_pet);
displayView.setText("Number of rows in pets database table: " + cursor.getCount());
} finally {
// Always close the cursor when you're done reading from it. This releases all its
// resources and makes it invalid.
cursor.close();
}
}
}
PetDbHelper.java
public class PetDbHelper extends SQLiteOpenHelper {
public static final String LOG_TAG = PetDbHelper.class.getSimpleName();
/**
* Name of the database file
*/
private static final String DATABASE_NAME = "shelter.db";
/**
* Database version. If you change the database schema, you must increment the database version.
*/
private static final int DATABASE_VERSION = 1;
/**
* Constructs a new instance of {#link PetDbHelper}.
*
* #param context of the app
*/
public PetDbHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
/**
* This is called when the database is created for the first time.
*/
#Override
public void onCreate(SQLiteDatabase db) {
// Create a String that contains the SQL statement to create the pets table
String SQL_CREATE_PETS_TABLE = "CREATE TABLE " + PetContract.PetEntry.TABLE_NAME + " ("
+ PetContract.PetEntry._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ PetContract.PetEntry.COLUMN_PET_NAME + " TEXT NOT NULL, "
+ PetContract.PetEntry.COLUMN_PET_BREED + " TEXT, "
+ PetContract.PetEntry.COLUMN_PET_GENDER + " INTEGER NOT NULL, "
+ PetContract.PetEntry.COLUMN_PET_WEIGHT + " INTEGER NOT NULL DEFAULT 0);";
// Execute the SQL statement
db.execSQL(SQL_CREATE_PETS_TABLE);
}
/**
* This is called when the database needs to be upgraded.
*/
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// The database is still at version 1, so there's nothing to do be done here.
}
}
PetContract.java
public final class PetContract {
private PetContract() {}
public static final class PetEntry implements BaseColumns {
public static final String TABLE_NAME = "pets";
public static final String _ID = BaseColumns._ID;
public static final String COLUMN_PET_NAME = "name";
public static final String COLUMN_PET_BREED = "breed";
public static final String COLUMN_PET_GENDER = "gender";
public static final String COLUMN_PET_WEIGHT = "weight";
/* Possible values for gender. */
public static final int GENDER_UNKNOWN = 0;
public static final int GENDER_MALE = 1;
public static final int GENDER_FEMALE = 2;
}
}
CommonSQLiteUtilities.java
public class CommonSQLiteUtilities {
public static final boolean ERROR_CHECKING_ON = true;
public static final boolean ERROR_CHECKING_OFF = false;
// SQLite MASTER TABLE definitions
static final String SQLITE_MASTER = "sqlite_master";
static final String SM_TABLE_TYPE_COLUMN = "type";
static final String SM_NAME_COLUMN = "name";
static final String SM_TABLENAME_COLUMN = "tbl_name";
static final String SM_ROOTPAGE_COLUMN = "rootpage";
static final String SM_SQL_COLUMN = "sql";
static final String SM_TYPE_TABLE = "table";
static final String SM_TYPE_INDEX = "index";
static final String PRAGMA_STATEMENT = "PRAGMA ";
static final String PRAGMA_DATABASELIST = "database_list";
static final String PRAGMA_USERVERSION = "user_version";
static final String PRAGMA_ENCODING = "encoding";
static final String PRAGMA_FOREIGNKEYLIST = "foreign_key_list";
static final String PRAGMA_INDEXINFO = "index_info";
static final String PRAGMA_INDEXLIST = "index_list";
static final String PRAGMA_TABLEINFO = "table_info";
static final String PRAGMA_DBLIST_SEQ_COL = "seq";
static final String PRAGMA_DBLIST_NAME_COL = "name";
static final String PRAGMA_DBLIST_FILE_COL = "file";
static final String PRAGMA_TABLEINFO_CID_COL = "cid";
static final String PRAGMA_TABLEINFO_NAME_COl = "name";
static final String PRAGMA_TABLEINFO_TYPE_COL = "type";
static final String PRAGMA_TABLEINFO_NOTNULL_COL = "notnull";
static final String PRAGMA_TABLEINFO_DEFAULTVALUE_COL = "dflt_value";
static final String PRAGMA_TABLEINFO_PRIMARYKEY_COL = "pk";
static final String CSU_TAG = "SQLITE_CSU";
private CommonSQLiteUtilities() {}
/**
* Write Database information to the log;
* Information wrttien is:
* the database path, (will/should show connected databases)
* the version number (note! user version i.e. version coded in DBHelper),
* the tables in the database (includes android_metadata but not sqlite_master),
* the columns of the tables
* #param db The SQLite database to be interrogated
*/
public static void logDatabaseInfo(SQLiteDatabase db) {
// Issue PRAGMA database_list commnand
Cursor dblcsr = db.rawQuery(PRAGMA_STATEMENT + PRAGMA_DATABASELIST,null);
// Write databases to the log
while (dblcsr.moveToNext()) {
Log.d(CSU_TAG,"DatabaseList Row " + Integer.toString(dblcsr.getPosition() + 1) +
" Name=" + dblcsr.getString(dblcsr.getColumnIndex(PRAGMA_DBLIST_NAME_COL)) +
" File=" + dblcsr.getString(dblcsr.getColumnIndex(PRAGMA_DBLIST_FILE_COL))
);
}
dblcsr.close();
// Issue PRAGMA user_version to get the version and write to the log
//Note! to set user_version use execSQL not rawQuery
Cursor uvcsr = db.rawQuery(PRAGMA_STATEMENT + PRAGMA_USERVERSION,null);
while (uvcsr.moveToNext()) {
Log.d(CSU_TAG,"Database Version = " +
Integer.toString(uvcsr.getInt(uvcsr.getColumnIndex(PRAGMA_USERVERSION))));
}
uvcsr.close();
// Select all table entry rows from sqlite_master
Cursor tlcsr = db.rawQuery("SELECT * FROM " +
SQLITE_MASTER + " WHERE " +
SM_TABLE_TYPE_COLUMN + "='" + SM_TYPE_TABLE + "'"
,null);
// For each table write table information to the log
// (inner loop gets column info per table)
while (tlcsr.moveToNext()) {
String current_table = tlcsr.getString(tlcsr.getColumnIndex(SM_TABLENAME_COLUMN));
Log.d(CSU_TAG,
"Table Name = " + current_table +
" Created Using = " + tlcsr.getString(tlcsr.getColumnIndex(SM_SQL_COLUMN)),
null
);
// Issue PRAGMA tabel_info for the current table
Cursor ticsr = db.rawQuery(PRAGMA_STATEMENT + PRAGMA_TABLEINFO +
"(" + current_table + ")",
null
);
// Write column info (see headings below) to the log
while (ticsr.moveToNext()) {
Log.d(CSU_TAG,"Table = " +
current_table +
" ColumnName = " +
ticsr.getString(ticsr.getColumnIndex(PRAGMA_TABLEINFO_NAME_COl)) +
" ColumnType = " +
ticsr.getString(ticsr.getColumnIndex(PRAGMA_TABLEINFO_TYPE_COL)) +
" Default Value = " +
ticsr.getString(ticsr.getColumnIndex(PRAGMA_TABLEINFO_DEFAULTVALUE_COL)) +
" PRIMARY KEY SEQUENCE = " + Integer.toString(
ticsr.getInt(ticsr.getColumnIndex(PRAGMA_TABLEINFO_PRIMARYKEY_COL))
)
);
}
ticsr.close();
}
tlcsr.close();
}
/**
* Generic get all rows from an SQlite table,
* allowing the existence of the table to be checked and also
* allowing the ROWID to be added AS a supplied string
*
* #param db The SQLiteDatabase
* #param tablename The name of the table from which the
* returned cursor will be created from;
* Note!
* #param use_error_checking Whether ot not to try to detect errors
* currently just table doesn't exist,
* true to turn on, false to turn off
* ERROR_CHECKING_ON = true
* ERROR_CHECKING_OFF = false
* #param forceRowidAs If length of string passed is 1 or greater
* then a column, as an alias of ROWID, will be
* added to the cursor
* #return the extracted cursor, or in the case of the
* underlying table not existing an empty cursor
* with no columns
*/
public static Cursor getAllRowsFromTable(SQLiteDatabase db,
String tablename,
boolean use_error_checking,
String forceRowidAs) {
String[] columns = null;
// Tablename must be at least 1 character in length
if (tablename.length() < 1) {
Log.d(CSU_TAG,new Object(){}.getClass().getEnclosingMethod().getName() +
" is finishing as the provided tablename is less than 1 character in length"
);
return new MatrixCursor(new String[]{});
}
// If use_error_checking is true then check that the table exists
// in the sqlite_master table
if (use_error_checking) {
Cursor chkcsr = db.query(SQLITE_MASTER,null,
SM_TABLE_TYPE_COLUMN + "=? AND "
+ SM_TABLENAME_COLUMN + "=?",
new String[]{SM_TYPE_TABLE,tablename},
null,null,null
);
// Ooops table is not in the Database so return an empty
// column-less cursor
if (chkcsr.getCount() < 1) {
Log.d(CSU_TAG,"Table " + tablename +
" was not located in the SQLite Database Master Table."
);
// return empty cursor with no columns
return new MatrixCursor(new String[]{});
}
chkcsr.close();
}
// If forcing an alias of ROWID then user ROWID AS ???, *
if(forceRowidAs != null && forceRowidAs.length() > 0) {
columns = new String[]{"rowid AS " +forceRowidAs,"*"};
}
// Finally return the Cursor but trap any exceptions
try {
return db.query(tablename, columns, null, null, null, null, null);
} catch (Exception e) {
Log.d(CSU_TAG,"Exception encountered but trapped when querying table " + tablename +
" Message was: \n" + e.getMessage());
Log.d(CSU_TAG,"Stacktrace was:");
e.printStackTrace();
return new MatrixCursor(new String[]{});
}
}
/**
* Create and return a Cursor devoid of any rows and columns
* Not used, prehaps of very little use.
* #param db The Sqlite database in which the cursor is to be created
* #return The empty Cursor
*/
private static Cursor getEmptyColumnLessCursor(SQLiteDatabase db) {
return new MatrixCursor(new String[]{});
}
/**
* Write column names in the passed Cursor to the log
* #param csr The Cursor to be inspected.
*/
public static void logCursorColumns(Cursor csr) {
Log.d(CSU_TAG,
new Object(){}.getClass().getEnclosingMethod().getName() +
" invoked. Cursor has the following " +
Integer.toString(csr.getColumnCount())+
" columns.");
int position = 0;
for (String column: csr.getColumnNames()) {
position++;
Log.d(CSU_TAG,"Column Name " +
Integer.toString(position) +
" is "
+ column
);
}
}
/**
* Write the contents of the Cursor to the log
* #param csr The Cursor that is to be displayed in the log
*/
public static void logCursorData(Cursor csr) {
int columncount = csr.getColumnCount();
int rowcount = csr.getCount();
int csrpos = csr.getPosition(); //<<< added 20171016
Log.d(CSU_TAG,
new Object(){}.getClass().getEnclosingMethod().getName() +
" Cursor has " +
Integer.toString(rowcount) +
" rows with " +
Integer.toString(columncount) + " columns."
);
csr.moveToPosition(-1); //Ensure that all rows are retrieved <<< added 20171016
while (csr.moveToNext()) {
String unobtainable = "unobtainable!";
String logstr = "Information for row " + Integer.toString(csr.getPosition() + 1) + " offset=" + Integer.toString(csr.getPosition());
for (int i=0; i < columncount;i++) {
logstr = logstr + "\n\tFor Column " + csr.getColumnName(i);
switch (csr.getType(i)) {
case Cursor.FIELD_TYPE_NULL:
logstr = logstr + " Type is NULL";
break;
case Cursor.FIELD_TYPE_FLOAT:
logstr = logstr + "Type is FLOAT";
break;
case Cursor.FIELD_TYPE_INTEGER:
logstr = logstr + " Type is INTEGER";
break;
case Cursor.FIELD_TYPE_STRING:
logstr = logstr + " Type is STRING";
break;
case Cursor.FIELD_TYPE_BLOB:
logstr = logstr + " Type is BLOB";
break;
}
String strval_log = " value as String is ";
String lngval_log = " value as long is ";
String dblval_log = " value as double is ";
String blbval_log = "";
try {
strval_log = strval_log + csr.getString(i);
lngval_log = lngval_log + csr.getLong(i);
dblval_log = dblval_log + csr.getDouble(i);
} catch (Exception e) {
strval_log = strval_log + unobtainable;
lngval_log = lngval_log + unobtainable;
dblval_log = dblval_log + unobtainable;
try {
blbval_log = " value as blob is " +
getBytedata(csr.getBlob(i),24);
} catch (Exception e2) {
e2.printStackTrace();
}
}
logstr = logstr + strval_log + lngval_log + dblval_log + blbval_log;
}
Log.d(CSU_TAG,logstr);
}
csr.moveToPosition(csrpos); // restore cursor position <<< added 20171016
}
/**
* Return a hex string of the given byte array
* #param bytes The byte array to be converted to a hexadecimal string
* #param limit the maximum number of bytes;
* note returned string will be up to twice as long
* #return The byte array represented as a hexadecimal string
*/
private static String getBytedata(byte[] bytes, int limit) {
if (bytes.length < limit) {
return convertBytesToHex(bytes);
} else {
byte[] subset = new byte[limit];
System.arraycopy(bytes,0,subset,0,limit);
return convertBytesToHex(subset);
}
}
// HEX characters as a char array for use by convertBytesToHex
private final static char[] hexarray = "0123456789ABCDEF".toCharArray();
/**
* Return a hexadecimal string representation of the passed byte array
* #param bytes The byte array to be represented.
* #return The string representing the byte array as hexadecimal
*/
private static String convertBytesToHex(byte[] bytes) {
char[] hexstr = new char[bytes.length * 2];
for (int i=0; i < bytes.length; i++) {
int h = bytes[i] & 0xFF;
hexstr[i * 2] = hexarray[h >>> 4];
hexstr[i * 2 + 1] = hexarray[h & 0xF];
}
return new String(hexstr);
}
}
activity_catalog.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".CatalogActivity">
<TextView
android:id="#+id/text_view_pet"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
I found out what the main issue was: I was using an emulator with an API 28. Apparently, anything above API 23 is an issue when trying to access databases.
So I made a new emulator API 23 and now I don't have any issues with the permissions etc.
#MikeT - this seems to have been why I was struggling with getting the permissions.
I am trying to write a dapper query for IN clause, but it's not working throwing casting error saying "Conversion failed when converting the nvarchar value 'A8B08B50-2930-42DC-9DAA-776AC7810A0A' to data type int." . In below query fleetAsset is Guid converted into string.
public IQueryable<MarketTransaction> GetMarketTransactions(int fleetId, int userId, int rowCount)
{
//Original EF queries which I am trying to convert to Dapper
//var fleetAsset = (from logicalFleetNode in _context.LogicalFleetNodes
// where logicalFleetNode.LogicalFleetId == fleetId
// select logicalFleetNode.AssetID).ToList();
////This query fetches guid of assetprofiles for which user having permissions based on the assets user looking onto fleet
//var assetProfileIds = (from ap in _context.AssetProfileJoinAccounts
// where fleetAsset.Contains(ap.AssetProfile.AssetID) && ap.AccountId == userId
// select ap.AssetProfileId).ToList();
var fleetAsset = _context.Database.Connection.Query<string>("SELECT CONVERT(varchar(36),AssetID) from LogicalFleetNodes Where LogicalFleetId=#Fleetid",
new { fleetId }).AsEnumerable();
//This query fetches guid of assetprofiles for which user having permissions based on the assets user looking onto fleet
var sql = String.Format("SELECT TOP(#RowCount) AssetProfileId FROM [AssetProfileJoinAccounts] AS APJA WHERE ( EXISTS (SELECT " +
"1 AS [C1] FROM [dbo].[LogicalFleetNodes] AS LFN " +
"INNER JOIN [dbo].[AssetProfile] AS AP ON [LFN].[AssetID] = [AP].[AssetID]" +
" WHERE ([APJA].[AssetProfileId] = [AP].[ID]) " +
" AND ([APJA].[AccountId] = #AccountId AND LogicalFleetId IN #FleetId)))");
var assetProfileIds = _context.Database.Connection.Query<Guid>(sql, new { AccountId = userId, FleetId = fleetAsset, RowCount=rowCount });
Dapper performs expansion, so if the data types match, you should just need to do:
LogicalFleetId IN #FleetId
(note no parentheses)
Passing in a FleetId (typically via an anonymous type like in the question) that is an obvious array or list or similar.
If it isn't working when you remove the parentheses, then there are two questions to ask:
what is the column type of LocalFleetId?
what is the declared type of the local variable fleetAsset (that you are passing in as FleetId)?
Update: test case showing it working fine:
public void GuidIn_SO_24177902()
{
// invent and populate
Guid a = Guid.NewGuid(), b = Guid.NewGuid(),
c = Guid.NewGuid(), d = Guid.NewGuid();
connection.Execute("create table #foo (i int, g uniqueidentifier)");
connection.Execute("insert #foo(i,g) values(#i,#g)",
new[] { new { i = 1, g = a }, new { i = 2, g = b },
new { i = 3, g = c },new { i = 4, g = d }});
// check that rows 2&3 yield guids b&c
var guids = connection.Query<Guid>("select g from #foo where i in (2,3)")
.ToArray();
guids.Length.Equals(2);
guids.Contains(a).Equals(false);
guids.Contains(b).Equals(true);
guids.Contains(c).Equals(true);
guids.Contains(d).Equals(false);
// in query on the guids
var rows = connection.Query(
"select * from #foo where g in #guids order by i", new { guids })
.Select(row => new { i = (int)row.i, g = (Guid)row.g }).ToArray();
rows.Length.Equals(2);
rows[0].i.Equals(2);
rows[0].g.Equals(b);
rows[1].i.Equals(3);
rows[1].g.Equals(c);
}