I want to log SQL Queries, to examine what exactly is my LINQ queries doing to understand how can I improve it.
But I can't find how to logging it.
I did it like this:
Change DbContextConfigurer in EntityFramework project
as:
public static void Configure(DbContextOptionsBuilder<TestDbContext> builder, string connectionString, **ILoggerFactory loggerFactory = null**)
{
**builder.UseLoggerFactory(loggerFactory);**
builder.UseSqlServer(connectionString);
}
Then add in file MyProjectEntityFrameworkCoreModule.cs into PreInitiallize section
public override void PreInitialize()
{
if (!SkipDbContextRegistration)
{
Configuration.Modules.AbpEfCore().AddDbContext<TestDbContext>(options =>
{
if (options.ExistingConnection != null)
{
TestDbContextConfigurer.Configure(options.DbContextOptions, options.ExistingConnection);
}
else
{
**var loggerFactory = IocManager.Resolve<ILoggerFactory>();**
TestDbContextConfigurer.Configure(options.DbContextOptions, options.ConnectionString,**loggerFactory**);
}
});
}
//Uncomment below line to write change logs for the entities below:
//Configuration.EntityHistory.Selectors.Add("TestEntities", typeof(OrganizationUnit), typeof(Role), typeof(Tenant));
}
If you are using MSSQL with EF and intend to troubleshoot how LINQ is being translated into SQL statement. You can try SQL Profiler that comes together with MSSQL Database Engine
With SQL Profiler, you are able to record and trace tsql event in it. With proper isolation of the LINQ call in your application, you can trace the SQL statement received by the Database engine.
https://learn.microsoft.com/en-us/sql/relational-databases/event-classes/tsql-event-category?view=sql-server-2017
Related
I'm trying to migration EF to Dapper and I'm looking for a better and efficient way on how to migrate existing linq expressions "IQueryable" to use Dapper.
Ex:
public class MyDbContext : DbContext
{
public DbSet<MyEntity> MyEntity { get; set; }
+20 more entities..
}
// Inside repository
using (var context = new MyDbContext())
{
context.MyEntity.Where( x => x.Id == 1) // How can I easily migrate this linq to Dapper?
}
The above code is a simple example only of what I'm trying to migrate. Some of those queries are mix of simple and complex. Currently, I have 20+ repositories and 20+ DbSet in MyDbContext that used that kind of approach inside repositories.
I searched in the internet and I haven't found a better approach. So far the only way to do this is to convert linq into query string one by one and use it in Dapper. It is doable but tedious and huge effort. Performance is my biggest concern why I'am migrating to Dapper.
Does anyone has a better way to do this than what I'm currently thinking?
I found a medicine to my own problem. Instead of intercepting the query, I allow to pass the predicate and create Linq like function same with existing.
public class QueryLinq
{
private readonly IDatabase _database;
public QueryLinq(IDatabase database)
{
_database = database; // Dapper implementation
}
public IEnumerable<T> Where<T>(Func<T,bool> predicate)
{
var enumerable = _database.Query<T>();
return enumerable(predicate);
}
}
// Existing Repository
public class MyRepository
{
private readonly QueryLinq _queryLinq;
public MyRepository(QueryLinq queryLinq)
{
_queryLinq = queryLinq;
}
public IEnumerable<MyEntity> SelectMyEntity()
{
// Before
// using (var context = new MyDbContext())
// {
// context.MyEntity.Where( x => x.Id == 1);
// }
// Now
return _queryLinq.Where<MyEntity>( x => x.Id == 1);
}
}
In this approach, I don't need to worry about existing queries.
Update 8/16/2018: for the complete details of this approach kindly visit here.
You can use Entity Framework Logging to output the generated SQL to the Visual Studio console. It's as simple as adding:
_context.Database.Log = x => Trace.WriteLine(x);
to your service or respository class(es).
I am doing exactly what you're doing, and for the same reason. You'll see that the SQL that LINQ generates can be sub-optimal so directly copying the same sub-optimal SQL for Dapper to use seemed to me like a pointless exercise.
What I've done is identify the LINQ queries that perform the worst, and rewrite them in SQL - from scratch - for use with Dapper. What I've ended up with is a combination of LINQ and Dapper throughout the system, benefitting from the strengths of both approaches ie LINQ's rapid development, and the performance gains of Dapper and optimised SQL queries.
We are using the awesome & fast OrmLite (ServiceStack) library as our microORM to connect to our PostgreSQL database.
We have TDE encryption enabled in our PostgreSQL database. To ensure that the relevant data is decrypted before we query, we need to execute the following:
Db.ExecuteSql(string.Format("SELECT pgtde_begin_session('{0}');", tdeKey));
and at the end:
Db.ExecuteSql("SELECT pgtde_end_session();");
Instead of inserting these into each of our RequestDto methods, can we instead ensure that these sql statements are executed before and after each call.
You can try using an OrmLite Exec Filter, with something like:
public class PgSqlSecureSessionFilter : OrmLiteExecFilter
{
public override T Exec<T>(IDbConnection db, Func<IDbCommand, T> filter)
{
try
{
db.Execute("SELECT pgtde_begin_session(#tdeKey)", new { tdeKey });
return base.Exec(db, filter);
}
finally {
db.Execute("SELECT pgtde_end_session();");
}
}
}
OrmLiteConfig.ExecFilter = new PgSqlSecureSessionFilter();
Can u tell me what is the problem?
If you are using two different instances of the DbContext (the db variable as you named it) then nothing will be saved when you call SaveChanges on a context different than the one where your entities are tracked. You need to use the Attach method first.
db.customer_images.Attach(item);
db.SaveChanges();
However I think in your case you can avoid the attach step if you refactor a bit you code and don't use the DbContext from the entity itself.
Before going through my answer, you must check, if you are attaching the item as shown in excepted answer or check this code:.
if (dbStudentDetails != null && dbStudentDetails.Id != 0)
{
// update scenario
item.Id = dbStudentDetails.Id;
_context.Entry(dbStudentDetails).CurrentValues.SetValues(item);
_context.Entry(dbStudentDetails).State = EntityState.Modified;
}
else
{
// create scenario
_context.StudentDetails.Add(item);
}
await _context.SaveChangesAsync();
If above solution doesn't work, then check the below answer.
Saw a very wired issue, and thought to must answer this. as this can
be a major issue if you have lots of constraints and indexes in your
SQL.
db.SaveChanges() wasn't throwing any error, but not working (I have tried Exception or SqlException). This was not working because the Unique constraint was not defined properly while creating the Entity Models.
How you can Identified the issue:
I connected my SQL Server and opened the SQL Profiler.
Just before the db.SaveChanges(), I cleared all my profiler logs and ran the db.SaveChanges(). It logged the statement. I copied the script from the profiler and ran the script in SQL Server.
And bingo, I can see the actual error, which is being thrown at SQL Server side.
(images: have some hints, how you can get the execute statement from Profiler and run on sql server)
What you can do For Entity Framework Core:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Students>().HasIndex(p => new { p.RollNumber, p.PhoneNumber }).IsUnique(true).IsClustered(false).HasDatabaseName("IX_Students_Numbers");
}
What you can do For Entity Framework 6 and below:
using System.Data.Entity.ModelConfiguration;
internal partial class StudentsConfiguration : EntityTypeConfiguration<Students>
{
public StudentsConfiguration()
{
HasIndex(p => new { p.RollNumber, p.PhoneNumber }).IsUnique(true).IsClustered(false).HasName("IX_Students_Numbers");
}
}
Try to query your entity by Id, eg:
entity = this.repo.GetById(item.id);
entity.is_front = false;
if (dbSaveChanges() > 0)
{
....
}
I'm trying to delete all database entries for a Spring Roo entity. When I look at *_Roo_Entity.aj it seems as if there is no "delete all" method. I tried to implement it myself (Licences is the name of the Roo entity. Don't mind the naming. It was reverese engineered from a database and may be changed later):
public static int Licences.deleteAll() {
return entityManager().createQuery("delete from Licences o").executeUpdate();
}
It compiles just fine but when I call Licences.deleteAll() I get the following exception:
org.springframework.dao.InvalidDataAccessApiUsageException: Executing an update/delete query;
nested exception is javax.persistence.TransactionRequiredException: Executing an update/delete query (NativeException)
Adding #Transactional doesn't make a difference.
What am I missing here?
Is this approach completely wrong and I need to implement it like this:
public static void Licences.deleteAll() {
for (Licences licence : findAllLicenceses()) {
licence.remove();
}
}
This works, but is JPA smart enough to translate this into a delete from licences query or will it create n queries?
#Transactional doesn't work on static function
change
public static int Licences.deleteAll() {
return entityManager().createQuery("delete from Licences o").executeUpdate();
}
to
public int Licences.deleteAll() {
return entityManager().createQuery("delete from Licences o").executeUpdate();
}
https://jira.springsource.org/browse/SPR-5999
Bye
JPA does not have a delete all functionality. (even not with JQL!)
At least there are only three ways:
The loop, like you did
A JPQL Query see: JPQL Reference: 10.2.9. JPQL Bulk Update and Delete
A native SQL Query, but this will cause many problems with Entity Manager caches!
BTW: It seams that you are using AspectJ to attach you delete method. - You can do this (even if I do not know, why not adding the static method direct to the Entity class), but you must not touch the Roo generated aj files!
public static int Licences.deleteAll() {
return new Licences().deleteAllTransactional();
}
#Transactional
private int Licences.deleteAllTransactional() {
if (this.entityManager == null) this.entityManager = entityManager();
return this.entityManager.createQuery("delete from Licences o").executeUpdate();
}
Is there any way to run a sql statement straight from the entity framework generated calls? Or will I have to create a procedure then call that via the entity framework?
Was Googling around for this myself the other day, this is the example I found hope it helps
static void ExecuteSql(ObjectContext c, string sql)
{
var entityConnection = (System.Data.EntityClient.EntityConnection)c.Connection;
DbConnection conn = entityConnection.StoreConnection;
ConnectionState initialState = conn.State;
try
{
if (initialState != ConnectionState.Open)
conn.Open();
using (DbCommand cmd = conn.CreateCommand())
{
cmd.CommandText = sql;
cmd.ExecuteNonQuery();
}
}
finally
{
if (initialState != ConnectionState.Open)
conn.Close();
}
}
In EF 4.0 this is pretty easy because there are new methods on the ObjectContext that allow you to execute store commands (i.e. SQL) directly:
See this: ExecuteStoreCommand
If you are still using EF 3.5 SP1 you can still execute a query directly against the database if you really want to like this:
var econn = ctx.Connection as EntityConnection;
var dbconn = econn.StoreConnection;
at this point you have access to a connection (dbconn) to the underlying database, so you can use normal ADO.NET code to execute queries etc.
Hope this helps
Alex
ExecuteStoreQuery<> and ExecuteStoreCommand is what you want:
using (NorthWindEntities ctx = new NorthWindEntities())
{
ctx.ExecuteStoreQuery<>()
ctx.ExecuteStoreCommand();
}
#Alex James, out of curiosity, would this be efficient to run a full text sql bit of code, as in there should be no performance overhead right? To say, running the same full text sql code straight as a query in sql management studio.