What if you don't need a parameter when querying with Dapper? - dapper

I have one query that does a count/group by where I don't need a parameter (there is no where clause).
What is the syntax to run a parameterless query with dapper?
var _results = _conn.Query<strongType>("Select Count(columnA) as aCount, ColumnB, ColumnC from mytable group by ColumnB, ColumnC");
does not work.
I've tried it a few different ways but I still keep getting "ArgumentNullException was unhandled by user code".
Tried to figure it out myself, searched all over and I'm giving up. Thanks in advance.
Edit: Below is the line of code from SqlMapper.cs that throws the error. It's line 1334
il.Emit(OpCodes.Newobj, typeof(T).GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null));
The error details: Value cannot be null. Parameter name: con

Mapping a single result back works just fine:
var a = cnn.Query<int>("select 1").Single()
// a is 1
You may face trouble if somehow your query returns no results, for example:
select count(Id) from
(
select top 0 1 as Id, 2 as Title
) as X
group by Title
return 0 results, so doing a Single on an empty result set is not going to work.

try
var _results = _conn.Query("Select columnB, Count(columnA) C from mytable group by columnB");
int ColumnB = ((int)_results[0].ColumnB);
int C = ((int)_results[0].C);

Value cannot be null. Parameter name: con
This is error is thrown by several dynamic ORMs including Dappper, PetaPoco and Massive but it's usually the same problem: Make sure you're using the [Ignore] attribute on the properties you don't want to include. This includes properties inherited from base classes. The error is useless but that's what it means.

This error can occur because a property you're trying to set in your return object is get-only. Dapper, of course, requires being able to set all properties. You might consider having a separate database DTO object that then gets converted to your properly immutable domain object after reading from the database.
Change this:
public string MyProperty { get; }
to this:
public string MyProperty { get; set; }

Related

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.

JOOQ fails with PostgreSQL Custom Type as an Array: ERROR: malformed record literal

I have the following custom type on Postgres:
CREATE TYPE my_custom_type AS (
field_a VARCHAR,
field_b NUMERIC(10,3)
);
and the following table:
CREATE TABLE my_table
(
COL1 VARCHAR(120) NOT NULL,
CUSTOM_COLUMN my_custom_type,
CUSTOM_COLUMN_ARRAY my_custom_type[]
);
Everything works fine when I use my custom type with JOOQ:
#Test
public void testWithoutArray(){
MyTableRecord record = dsl.newRecord(MyTable.MY_TABLE);
record.setCol1("My Col1");
MyCustomType customType = new MyCustomType();
customType.setFieldA("Field A Val");
customType.setFieldB(BigDecimal.ONE);
record.setCustomColumn(customType);
record.store();
}
However, when I try to set some value in the field mapped to a custom type array, I have the following error:
#Test
public void testWithArray(){
MyTableRecord record = dsl.newRecord(MyTable.MY_TABLE);
record.setCol1("My Col1");
MyCustomTypeRecord customType = new MyCustomTypeRecord();
customType.setFieldA("Field A Val 1");
customType.setFieldB(BigDecimal.ONE);
MyCustomTypeRecord customType2 = new MyCustomTypeRecord();
customType2.setFieldA("Field A Val 2");
customType2.setFieldB(BigDecimal.TEN);
record.setCustomColumnArray(new MyCustomTypeRecord[]{customType, customType2});
record.store();
}
org.jooq.exception.DataAccessException: SQL [insert into "my_table" ("col1", "custom_column_array") values (?, ?::my_custom_type[]) returning "my_table"."col1"]; ERROR: malformed record literal: "my_custom_type"(Field A Val 1, 1)"
Detail: Missing left parenthesis.
at org.jooq.impl.Utils.translate(Utils.java:1553)
at org.jooq.impl.DefaultExecuteContext.sqlException(DefaultExecuteContext.java:571)
at org.jooq.impl.AbstractQuery.execute(AbstractQuery.java:347)
at org.jooq.impl.TableRecordImpl.storeInsert0(TableRecordImpl.java:176)
at org.jooq.impl.TableRecordImpl$1.operate(TableRecordImpl.java:142)
at org.jooq.impl.RecordDelegate.operate(RecordDelegate.java:123)
at org.jooq.impl.TableRecordImpl.storeInsert(TableRecordImpl.java:137)
at org.jooq.impl.UpdatableRecordImpl.store0(UpdatableRecordImpl.java:185)
at org.jooq.impl.UpdatableRecordImpl.access$000(UpdatableRecordImpl.java:85)
at org.jooq.impl.UpdatableRecordImpl$1.operate(UpdatableRecordImpl.java:135)
at org.jooq.impl.RecordDelegate.operate(RecordDelegate.java:123)
at org.jooq.impl.UpdatableRecordImpl.store(UpdatableRecordImpl.java:130)
at org.jooq.impl.UpdatableRecordImpl.store(UpdatableRecordImpl.java:123)
The query generated by JOOQ debugg is the following:
DEBUG [main] org.jooq.tools.LoggerListener#debug:255 - Executing query : insert into "my_table" ("col1", "custom_column_array") values (?, ?::my_custom_type[]) returning "my_table"."col1"
DEBUG [main] org.jooq.tools.LoggerListener#debug:255 - -> with bind values : insert into "my_table" ("col1", "custom_column_array") values ('My Col1', array[[UDT], [UDT]]) returning "my_table"."col1"
Am I missing some configuration or is it a bug?
Cheers
As stated in the relevant issue (https://github.com/jOOQ/jOOQ/issues/4162), this is a missing piece of support for this kind of PostgreSQL functionality. The answer given in the issue so far is:
Unfortunately, this is an area where we have to work around a couple of limitations of the PostgreSQL JDBC driver, which doesn't implement SQLData and other API (see also pgjdbc/pgjdbc#63).
Currently, jOOQ binds arrays and UDTs as strings. It seems that this particular combination is not yet supported. You will probably be able to work around this limitation by implementing your own custom data type Binding:
http://www.jooq.org/doc/latest/manual/code-generation/custom-data-type-bindings/

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

c++ builder: getting values via ADOQuery using SELECT

The question is as for delphi coders as for c++ builder coders, cuz I'm using the same components.
I'm trying to fill labels on the form by the data from database. I do a SELECT query via TADOQuery. But when I try to get a result, I always get an error like "ADOQuery1: Field 'count' not found".
'id' passed to the function is an autoincrement field value, which is EXACTLY exists in database (it was got via DBLookupComboBox). Also, executing the query manually to show result in DBGrid is successfull.
Querying without parameters and writing 'id' value to query string fails too.
What's the problem? Here's the code.
void TSellForm::LoadData(int id) {
TADOQuery* q = DataModule1->ADOQuery1;
q->Active = false;
try
{
q->SQL->Text = "select * from drugs where(id=:id)";
q->Parameters->ParamByName("id")->Value = IntToStr(id);
q->ExecSQL();
this->LabelAvail->Caption = q->FieldByName("count")->Value;
}
catch (Exception* e) {
MessageBox(NULL, PChar(WideString(e->Message)),
L"Exception", MB_OK|MB_ICONWARNING);
}
q->SQL->Clear();
}
ExecSQL is only used for SQL statements that don't return a recordset, and to determine the results you use RowsAffected.
For SELECT statements (which return a recordset), you use Open or set Active to true.
Also, count is a reserved word in most SQL dialects (as in SELECT Count(*) FROM ..., so if you have a column with that name you're going to need to escape it, typically by using either [] or double-quotes around it or by aliasing it in the SELECT itself.
ADOQuery1->Close();
ADOQuery1->SQL->Text= "SELECT * FROM reportTble WHERE (firstName =:firstName) " ;
ADOQuery1->Parameters->ParamByName("firstName")->Value = textBox->Text ;
ADOQuery1->Open();
This is how you can use ADOQuery

Unable to select just certain columns from table with Entity Framework - get anonymous type error

I am trying to select only certain columns from a table using EF 6.1. However, it won't let me pull back just the columns I want. I have to pull back every column from the table which has 14,000 rows so the query takes ~30 seconds. The column that kills the query is a NVARCHAR in the table. But with EF it's all or nothing. I am using IEnumerable also. Perhaps I should be using IQueryable?>
Using this query I get an anonymous type error:
Using db As Ctx = New Ctx
Dim postcount = db.be_Posts.Count
posts = db.be_Posts.Select(Function(S) New With {S.DateCreated, S.Description, S.PostRowID, S.Title}).OrderByDescending(Function(x) x.DateCreated)
Return posts.ToList
End Using
Error:
Unable to cast object of type 'System.Data.Entity.Infrastructure.DbQuery`1[VB$AnonymousType_0`4[System.DateTime,System.String,System.Int32,System.String]]' to type 'System.Collections.Generic.IEnumerable`1
This works but is getting all the records and the columns I don't need:
Using db As Ctx = New Ctx
Dim postcount = db.be_Posts.Count
posts = db.be_Posts.OrderByDescending(Function(x) x.DateCreated).ToList
Return posts
End Using
What I would do is:
Create PostSummaryDto class:
public class PostSummaryDto
{
public DateTime DateCreated { get; set; }
...rest of fields...
}
Use PostSummaryDto class in query:
New PostSummaryDto { DateCreated = S.DateCreated, ...}
Define return type of function as IEnumerable<PostSummaryDto>.
I am not a fan of Visual Basic, so I am not sure if returning anonymous types is allowed, but I believe it is good custom to define return types clearly.

Resources