Is there any possibility to use DapperORM with (Azure) SQL 2016 Always Encrypted? Is there any documentation how to use and best practises?
especially how to deal with the new parameter property input direction and input length?
The following links will help you get started on Always Encrypted.
Getting started with Always Encrypted
Parameterization For
Always Encrypted
I have not used Dapper ORM, but, as long as you have the ability to enable Always Encrypted using the connection string and to parameterize your literals you should be fine.
Here is a quick sample that I tried. Note Column Encryption Setting=Enabled in the connection string which enables Always Encrypted for the given connection.
private static readonly string connectionString = #"Data Source=.;Initial Catalog=dbName;Integrated Security=true;Connection Timeout=60;Column Encryption Setting=Enabled";
static void Main(string[] args)
{
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
int id = 1;
var dog = conn.Query<Dog>("select age, name, weight, idcol from DogTable where idcol = #Id", new { Id = id });
}
}
public class Dog
{
public int? age { get; set; }
public int idcol { get; set; }
public string name { get; set; }
public float? weight { get; set; }
public int IgnoredProperty { get { return 1; } }
}
To add to Nikhil's answer, it is possible and the resources he cites are helpful, however the parameterization article might be a little misleading, I'll include a snippet that I just got working in case it helps. You do not have to use a DECLARE #SSN... in your sql like you would in SSMS, the blow works just fine for me once I fixed my type issues (see paragraph after the code block).
string sql = "SELECT * from dob.ExampleTable WHERE IsActive = 1 SSN = #SSN";
var results = await this.DbConnection.QueryAsync(sql, new
{
SSN = 999999999
});
Also, keep an eye out for mismatched data types. I was not able to make char or varchar work as the target type for my SSN column using Dapper (I was able to use straight ADO.NET configuring the column explicitly as CHAR or VARCHAR but Dapper seems to assume NVARCHAR(4000) for all string fields, which resulted in an error using Dapper). NVARCHAR and NCHAR worked fine. I think it has something to do with the fact that when you encrypt the column, it changes the "real" datatype to NCHAR(50) and something about the conversion of dapper from nvarchar(4000)=>CHAR(9)=>NCHAR(50) wasn't working, but only in Dapper.
Related
I have this setting in my model:
[StringLength(250)]
public string Comment { get; set; }
to set the maximum length to 250 in the database which is great.
However it's set as nvarchar(250) when the database person was expecting varchar(250).
Can somebody please tell me how to set it as a varchar from the model as opposed to an nvarchar?
Use ColumnAttribute to give the datatype
[Column(TypeName = "VARCHAR")]
[StringLength(250)]
public string Comment { get; set; }
Or use fluent API
modelBuilder.Entity<MyEntity>()
.Property(e => e.Comment).HasColumnType("VARCHAR").HasMaxLength(250);
For some reason this older post keeps coming up in my search... so just FYI, using EF6 Core it's combined. The above answer errors out for me.
[Column(TypeName = "VARCHAR(250)")]
public string Comment {get;set;}
Visual Studio 2022 using Net 6 and EF Core 6, database first using the -DataAnnotations parameter creates the following attributes
/* Nullable column */
[StringLength(250)]
[Unicode(false)]
public string? Comment { get; set; }
/* Non-Nullable column */
[StringLength(250)]
[Unicode(false)]
public string Comment { get; set; } = null!;
I have created a function in postgres that takes a UDTT[] as an importing parameter, and want to eventually insert that data into a Table
Example Udtt
create type udtt_mytype as
(
id uuid,
payload int
);
And then an example Function is something akin to
CREATE OR REPLACE FUNCTION dbo.p_dothething(p_import udtt_mytype[])
RETURNS void
LANGUAGE plpgsql
AS $function$
BEGIN
insert into mytab select * from unnest($1)
RETURN;
END
$function$;
My C# backend presently looks like
public class udtt_mytype
{
[PgName("id")]
public Guid id{ get; set; }
[PgName("payload ")]
public int payload { get; set; }
}
var payload = CreateAndFillUdttMyType();
var conn = new NpgsqlConnection();
conn.Open();
var transaction = conn.BeginTransaction();
conn.MapComposite<udtt_mytype>("udtt_mytype");
var command = new NpgsqlCommand("dbo.p_dothething", conn);
command.CommandType = CommandType.StoredProcedure;
Object[] objArray = new Object[1];
objArray[0] = new NpgsqlParameter { ParameterName = "p_import",
Value = payload , NpgsqlDbType = NpgsqlTypes.NpgsqlDbType.Array |
NpgsqlTypes.NpgsqlDbType.Composite };
command.Parameters.AddRange(objArray);
var result = command.ExecuteScalar();
transaction.Commit();
conn.Close();
While the above works, it is pretty non-performant compared to a similiar UDTT -> SQL StoredProcedure. Prior to our NPGSQL implementation, this was <1 second, but now i seem to be seeing about a 6seconds per 6k rows (whereas the common usages for this end up being much higher numbers than that).
Using some timestamping and returning from the SP, i see that the processing of the data in the function isnt the issue at all..it appears to entirely be transfer time of the payload. In this particular case its a simple array of UDTT_MYTYPE's, and with a single object, execution is instantaneous, but w/ 6k, its up to the 6-7 seconds range. And this performance persists even if i pass it off to an empty function (removing the cost of the unnest/insert).
In reality, udtt_mytype has 12 columns of various types, but we are still talking about a relatively 'shallow' object.
I have attempted to compare this to NPGSqls' documentation on Bulk copy (found here http://www.npgsql.org/doc/copy.html), and that implementation seemed to be even slower than this, which seems contradictive.
Is postgres typically this much slower than MSSQL, or is there something that may be limiting xfer rate of data that im not aware of? Obviously no one can speak for my network connectivity/hardware setup, but anyone that may have converted between the two, was a performance increase seen along this same scale?
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.
I am retrieving data from SQL Server from a StoredProcedure using Dapper and I'm getting error
Specified cast is not valid.
and details:
Error parsing column 4 (SubTotal=0.00 - Decimal)
On SQL Server side the column SubTotal is decimal(18, 2) NULLABLE and on .NET side it's decimal?. The data being retrieved is 0.00.
I checked this answer: Dapper,decimal to double? Error parsing column X
As per answer, I replaced
il.Emit(OpCodes.Ldtoken, unboxType);
with
il.Emit(OpCodes.Ldtoken, Nullable.GetUnderlyingType(unboxType) ?? unboxType);
on line 2360 and still getting the same error.
Anyone has any ideas about this? Thanks.
Update:
I tried making column non-nullable. Also tried changing column to float (on SQL Server) and double (on .NET side). None of these worked and I was getting the same error. Then I changed column to int and now code works fine. However, I'm working with monetary values and would like to use floating point numbers. Will investigate further...
I'm executing a stored procedure as follows
var transaction = this.db.Query<PaymentTransactions>("usp_PaymentTransactionsGetSingleIfPaid", new { registrationId }, commandType: CommandType.StoredProcedure);
The relevant part of the stored procedure that returns information is below.
SELECT * FROM PaymentTransactions WHERE RegistrationId = #registrationId AND TransactionStatus = 'SUCCESS';
UPDATE 2:
Dapper is working fine. Maybe there was something wrong with my dev environment. All it took was VS restart.
Don't laugh, but I had this exact same problem with Dapper in an ASP.NET MVC project and the solution as in the comment from #erdinger worked also for me:
Close Visual Studio
Start Visual Studio again
The problem was fixed this way...
Seems like this is not Dapper specific, as I just verified the below snippet works as expected.
Try enumerating your column names explictly (instead of select *) so that the procedure returns exactly what should be mapped to PaymentTransactions. Its possible there is another non-decimal column that is misnamed?
This is using Dapper v1.13 on .Net45:
Procedure:
create procedure dbo.Test
as
select [SubTotal] = cast('0.01' as decimal(18,2))
union all
select null;
Linqpad:
void Main()
{
using (IDbConnection cnn = GetOpenConnection())
{
var users = cnn.Query<Sale>("yak.dbo.test", new { }, commandType: CommandType.StoredProcedure);
users.Dump();
}
}
public static readonly string connectionString = "Data Source=.;Initial Catalog=tempdb;Integrated Security=True";
public static IDbConnection GetOpenConnection()
{
var connection = new SqlConnection(connectionString);
connection.Open();
return connection;
}
public class Sale
{
public decimal? SubTotal;
}
Returns:
Hi I have written code like this
#Id
#Column(nullable=false)
#GeneratedValue(strategy=GenerationType.AUTO)
public int getUserID() {
return UserID;
}
But I manually setting it from DAO like "e.setUserID(01);" to insert.Otherwise row not inserting Is there any process to get value to id and retrieve what value generated automatically. Im thinking i will get some help
Use the IDENTITY generation type instead of auto. Use a Long for id. I also recommend changing the name from UserID to userId. Do not forget the #Entity for the class name.
#Entity
public class MyClass{
private Long userId;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column
public Long getUserID(){
return userId;
}
//.. rest of class
}
Be very careful with the naming conventions and make sure your field names and types match the field names and types from the database.
Use
#GenericGenerator(name="generator", strategy="increment")
#GeneratedValue(generator="generator")