How do I write this Entity Framework LINQ Query as a Compiled Query?
var context = new SlxDbContext();
var userSet = context.Set<User>();
User user = userSet.Where(x => x.UserName == "gstrader").First();
There's no way to use CompiledQuery when you're using the DbContext API; CompiledQuery works only with ObjectContext. If you're using Code First, you're most likely using the DbContext API. And Microsoft recommends that you use the DbContext API in new projects even if you'll be working with Database First or Model First models.
But if you use EF5, it brings auto-compiled queries, which work very differently than CompiledQuery. Instead of your writing code to compile each query and then invoking each as needed, EF5 caches the generated SQL for you as a background process, then searches the cache for already compiled queries when you execute any query.
See:
http://blogs.msdn.com/b/adonet/archive/2012/02/14/sneak-preview-entity-framework-5-0-performance-improvements.aspx
and
http://www.devproconnections.com/article/entity-framework/entity-framework-5-143875
Unfortunately the version of EF you are using (code first), does not support compiled queries.
Please correct me if I'm wrong.
Some links:
How do I precompile an Entity Framework Code-First Query?
EF Code First DbContext and Compiled Queries
http://blogs.msdn.com/b/adonet/archive/2011/03/02/ef-4-1-is-coming-dbcontext-api-amp-code-first-rtw.aspx
UPDATE:
Here is a sample for compiled queries, but I think it's not going to work with Code First:
public static Shop CompiledGetShopById(Guid shopId)
{
using (DataContext dtx = new DataContext(ConfigProvider.ConnectionString)) {
return Compiled_GetById.Invoke(dtx, shopId);
}
}
private static Func<DataContext, Guid, Shop> Compiled_GetById =
Objects.CompiledQuery.Compile<DataContext, Guid, Shop>(
(DataContext db, Guid shopId) =>
(from item in db.Shops where item.ShopId == shopId)
.FirstOrDefault()
);
Related
I Have a Multi-Tenant application and how can I use Interception in Entity Framework 7?
In Entity Framework 6, exists Interception using System.Data.Entity.Infrastructure.Interception, but don't find in version 7 of the Entity Framework.
Here's an example -> https://azure.microsoft.com/en-us/documentation/articles/web-sites-dotnet-entity-framework-row-level-security/
Interception isn't implemented yet in EFCore. It is a backlog item (see https://github.com/aspnet/EntityFramework/wiki/Roadmap)
Although EF Core does not have Interceptors, it is possible to perform QueryFilters to ensure that all queries are filtered by the tenant id.
Gunnar Peipman has a number of articles that can help you understand how to use QueryFilters for a Multi-Tenant scenario.
http://gunnarpeipman.com/2017/08/ef-core-global-query-filters/
I have somewhat some issue.
In EF Core you can use interceptors, here's some sample code that may be of use:
using System.Data.Common;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.Extensions.DiagnosticAdapter;
public class CommandListener
{
[DiagnosticName("Microsoft.EntityFrameworkCore.Database.Command.CommandExecuting")]
public void OnCommandExecuting(DbCommand command, DbCommandMethod executeMethod, Guid commandId, Guid connectionId, bool async, DateTimeOffset startTime)
{
//call security or other methods here.
}
[DiagnosticName("Microsoft.EntityFrameworkCore.Database.Command.CommandExecuted")]
public void OnCommandExecuted(object result, bool async)
{
//call security or other methods here.
}
}
In the constructor of your repository you do the hooking
var listener = _context.GetService<DiagnosticSource>();
(listener as DiagnosticListener).SubscribeWithAdapter(new CommandListener());
Now when you query your dbContext e.g.:
_context.employees.Where(...
Then before this query is returned the above methods OnCommandExecuting and OnCommandExecuted are executed.
So you can somewhat imitate the override of SaveChanges in EF Core.
However one important thing to note is that the return result set from the query is not accessible in the OnCommandExecuting and OnCommandExecuted methods.
I am having a weird pattern of response time when using the Entity Framework for SQL communication.
This is from my web host:
This is from my local server:
It's the increase in response time I am worried about.
I have narrowed the problem down to one single line in code
Nop.Data > EfRepository.cs > public void Insert(T entity) > _entities.Add(entity);
Yes I know this very specific for the NopCommerce, but the point is really that I am looking her for help on how to debug this.
Are there some events I can catch that display the SQL being executed?
Or what other things can I do to find out more what is actually happening in the Entity Framework in that above command.
For debugging EF queries, the easiest thing is to cast the query to ObjectQuery and use ToTraceString:
var query = myContext.MyTable
.Where(r => r.Id == searchId)
.Select(r => r);
Console.WriteLine(((ObjectQuery)query).ToTraceString());
This will show the underlying SQL for the query, and you can run the queries manually to debug why they are slow. Here is the MSDN link:
http://msdn.microsoft.com/en-us/library/system.data.objects.objectquery.totracestring.aspx
If you're trying to get the SQL which is run when you call SaveChanges() on your context, it's not as easy. You could take a look at EFTracingProvider:
http://blogs.msdn.com/b/jkowalski/archive/2009/06/11/tracing-and-caching-in-entity-framework-available-on-msdn-code-gallery.aspx
Or, assuming you use SQL Server, you can go directly to SQL Profiler and capture the T-SQL statements (this is my preferred approach).
In EF6, you can also do this in the constructor of your dbcontext
Example
public BookServiceContext() : base("name=BookServiceContext")
{
// New code:
this.Database.Log = s => System.Diagnostics.Debug.WriteLine(s);
}
This will log to the console every SQL query EF generates. See this article for more information http://blog.oneunicorn.com/2013/05/08/ef6-sql-logging-part-1-simple-logging/
Another example might be very helpful for someone.
public class MyDbContext : DbContext
{
private readonly ILoggerFactory _loggerFactory;
public MyDbContext(DbContextOptions<MyDbContext> options, ILoggerFactory loggerFactory) : base(options)
{
_loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
// Enable logging
optionsBuilder.UseLoggerFactory(_loggerFactory);
if (System.Diagnostics.Debugger.IsAttached)
optionsBuilder.EnableSensitiveDataLogging();
base.OnConfiguring(optionsBuilder);
}
}
I've made a "generic" program that converts data from a db to another. It uses configuration files to define the conversion. It uses code like this:
static DbProviderFactory _srcProvFactory;
static DbProviderFactory _trgtProvFactory;
public static bool DoConversions()
{
try
{
if (!InitConfig())
return false;
_srcProvFactory = DbProviderFactories.GetFactory(GetConnectionClassTypeByDatabaseType(Preferences.SourceDatabaseType));
_trgtProvFactory = DbProviderFactories.GetFactory(GetConnectionClassTypeByDatabaseType(Preferences.TargetDatabaseType));
using (DbConnection srcCnctn = _srcProvFactory.CreateConnection(),
trgtCnctn = _trgtProvFactory.CreateConnection())
{
srcCnctn.ConnectionString = Preferences.SourceConnectionString;
srcCnctn.Open();
trgtCnctn.ConnectionString = Preferences.TargetConnectionString;
trgtCnctn.Open();
//DO STUFF
}
}
}
Above GetConnectionClassTypeByDatabaseType-method return strings like "System.Data.OracleClient" depending on config file.
The DO STUFF part calls methods like one below (there's many of these) to find out database table column properties from schema. This is needed cause Oracle, SQL server etc. handle these differently.
public static int GetColumnMaxStringLength(DbProviderFactory provFactory, DataRow schemaTableRow)
{
if (provFactory is OracleClientFactory)
{
return Convert.ToInt32(schemaTableRow["LENGTH"]);
}
else if // OTHER OPTIONS
...
throw new Exception(string.Format("Unsupported DbProviderFactory -type: {0}", provFactory.GetType().ToString()));
}
So how this is supposed to be fixed now when the build says these classes are obsolete? This was supposed to be kind of text book solution when I did this (Pro C# 2008 and the
.NET 3.5 Platform). Now I'm baffled.
Thanks in advance & Best Regards - Matti
ODP.NET or any of the other 3rd party ADO.NET driver providers:
ref: Comparison of 3rd Party Oracle .NET Providers
I am looking for a way to see what the sql is that my L2E code has generated for debugging purposes.
I have read a blogpost by Scott G. on a visualizer for Linq2SQL but I can't get it to work for L2E.
Do you know of some way to visualize the generated SQL from L2E?
I am using Visual Studio 2008 SP1 Professional.
The Class ObjectQuery has a ToTraceString() function. However, most queries that you write in LINQ are created as IQueryable so you first have to cast them to an ObjectQuery in order to use it.
or, if you define this extension method, you can use it with IQ
public static string ToTraceString<T>(this IQueryable<T> expression)
{
ObjectQuery<T> objectQuery = expression as ObjectQuery<T>;
if (objectQuery != null)
{
return objectQuery.ToTraceString();
}
return "";
}
...
//then you could use it like this
IQueryable<Record> records = db.Record.Where(r=>r.Value > x);
string generatedQuery = record.ToTraceString();
Try Sql Server Profile (if you have Sql Server installed).
Open a new Trace window and there you'll see all your queries issued against Sql Server.
Almost certainly a stupid question but I can't find the answer anywhere.
In the Getting Started tutorial the database is SQLite and so his session factory creation
is done using the SQLiteConfiguration class in the FluentNHibernate.Cfg.Db namespace
Great! But I don't see a Configuration class for using an Oracle database. How do I do this?
Cross-posted to the fluent NH mailing list (with answer)
This works for me. Hope this helps!
private static ISessionFactory CreateSessionFactory()
{
var cfg = OracleClientConfiguration.Oracle9
.ConnectionString(c =>
c.Is("DATA SOURCE=<<NAME>>;PERSIST SECURITY INFO=True;USER ID=<<USER_NAME>>;Password=<<PASSWORD>>"));
return Fluently.Configure()
.Database(cfg)
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<CLASS_NAME>().ExportTo(#".\"))
.ExposeConfiguration(BuildSchema)
.BuildSessionFactory();
}
private static void BuildSchema(NHibernate.Cfg.Configuration config)
{
// this NHibernate tool takes a configuration (with mapping info in)
// and exports a database schema from it
new SchemaExport(config)
.Create(false, true);
}
Does this helps you?
http://tiredblogger.wordpress.com/2008/12/04/persistanceconfiguration-for-oraclefluent-nhibernate/
Edit: The code mentioned uses the ConnectionStringExpression class which no longer exists in Fluent NHibernate. However, that class isn't used for anything other than holding the OracleConfiguration _config field. You can safely, add the field to the OracleConnectionStringExpression class and remove it.
The remaining issue is that NHibernate will now for some reason look for components that are not in the current build of Oracle.DataAccess. If you want to deal with that you can do what tiredblogger did here.