Identify Code Origin from EF-Generated SQL? - entity-framework

What is the best way to identify the source of a (very) inefficient Entity Framework query when I only have the captured SQL available?

Assuming you're using some kind of logging framework, you could do something like this in your DbContext constructor:
this.Database.Log = sql =>
{
if (sql.Contains(/* part of the offending query */))
{
Logger.Log($"Found it! {Environment.StackTrace}")
}
}

Related

System.InvalidOperationException: Relational-specific methods can only be used when the context is using a relational database provider

System.InvalidOperationException:
Relational-specific methods can only be used when the context is using a relational database provider.
Getting the above mentioned error while using InMemoryDatabase for Test Case?
var msaContextOptions = new DbContextOptionsBuilder<MSA.DAL.MsaDbContext>()
.UseInMemoryDatabase(databaseName: "Get results")
.ConfigureWarnings(w => w.Ignore(InMemoryEventId.TransactionIgnoredWarning))
.Options;
Comparing with provider string is brittle - what if Microsoft changes to Microsoft.EntityFramework as it moves away from Core!
I would recommend to use
if (!context.Database.IsInMemory())
{
context.Database.Migrate();
}
or
if (context.Database.IsRelational())
{
context.Database.Migrate();
}
we have EF-related code in a separate nuget package that doesn't include Microsoft.EntityFrameworkCore.InMemory, therefore first option doesn't work for us.
As mentioned by other people I found skipping DBMigration is the best option for now.
I am running Database Migration when Database ProviderName is not InMemory.
if (context.Database.ProviderName != "Microsoft.EntityFrameworkCore.InMemory")
{
context.Database.Migrate();
}
In our case, the solution of #hemant-sakta didn't work. The cause for the error was that we set the auto-increment value in one of our database tables on seeding (we seed during migration).
The solution was to skip setting the auto-increment value when in Isolated Mode:
private static void SetAutoIncrementValue(MyContext context)
{
if (HostingEnvironment.IsEnvironment("Isolated")) return;
// auto increment code
}

EF4.1 based Repository and consistent view of data

using the unit of work and repository patterns i recently came across the issue, that changes to the unit of work are not reflected to subsequent queries. Example:
var ctx = DIContainer.Current.Resolve<IB2bContext>();
var rep = DIContainer.Current.Resolve<IRepository<Word>>(
new DependencyOverride<IB2bContext>(ctx));
rep.Add(new Word () { "One" };
rep.Add(new Word () { "Two" };
rep.GetAll().ToList().ForEach(i =>
Console.Write(i.text)); // nothing seen here
So in other words, unless i call SaveChanges() to persist the objects into the Database, i dont see them. Well ofcause i can fiddle around with the ChangeTracker and/or do things like context.Entry(foo).Property(...).CurrentValue. But does that play with a ddd like decoupling of layers? I dont think so. And where is my consistent dataview that once was called a database transaction?
Please enlighten me.
Armin
Your repository exposes some GetAll method. The method itself executes database query. If you want to see local data not inserted to database you must add them to result set. For example like:
public IEnumerable<Word> GetAll()
{
DbSet<Word> set = context.Set<Word>();
return set.AsEnumerable().Concat(set.Local);
}
The query execution is only responsible for returning persisted (real) data.

XML serialization errors when trying to serialize Entity Framework objects

I have entities that I am getting via Entity Framework. I'm using Code-First so they're POCOs. When I try to XML Serialize them using XmlSerializer, I get the following error:
The type
System.Data.Entity.DynamicProxies.Song_C59F4614EED1B7373D79AAB4E7263036C9CF6543274A9D62A9D8494FB01F2127
was not expected. Use the XmlInclude
or SoapInclude attribute to specify
types that are not known statically.
Anybody got any ideas on how to get around this (short of creating a whole new object)?
Just saying POCO doesn't really help (especially in this case since it looks like you're using proxies). Proxies come in handy in a lot of cases but make things like serialization more difficult since the actual object being serialized is not really your object but an instance of a proxy.
This blog post should give you your answer.
http://blogs.msdn.com/b/adonet/archive/2010/01/05/poco-proxies-part-2-serializing-poco-proxies.aspx
Sorry, I know I'm coming at this a bit late (a couple YEARS late), but if you don't need the proxy objects for lazy loading, you can do this:
Configuration.ProxyCreationEnabled = false;
in your Context. Worked like a charm for me. Shiv Kumar actually gives better insight into why, but this at least will get you back to work (again, assuming you don't need the proxies).
Another way that works independent of the database configuration is by doing a deep clone of your object(s).
I use Automapper (https://www.nuget.org/packages/AutoMapper/) for this in my code-first EF project. Here is some sample code that exports a list of an EF objects called 'IonPair':
public bool ExportIonPairs(List<IonPair> ionPairList, string filePath)
{
Mapper.CreateMap<IonPair, IonPair>(); //creates the mapping
var clonedList = Mapper.Map<List<IonPair>>(ionPairList); // deep-clones the list. EF's 'DynamicProxies' are automatically ignored.
var ionPairCollection = new IonPairCollection { IonPairs = clonedList };
var serializer = new XmlSerializer(typeof(IonPairCollection));
try
{
using (var writer = new StreamWriter(filePath))
{
serializer.Serialize(writer, ionPairCollection);
}
}
catch (Exception exception)
{
string message = string.Format(
"Trying to export to the file '{0}' but there was an error. Details: {1}",
filePath, exception.Message);
throw new IOException(message, exception);
}
return true;
}

SQL from EntityDataSource

Is there an easy way to see SQL statements generated by EntityDataSource?
SQL Server profiling/tracing is not an option here.
I used to use NHProf a profiler for NHibernate and it is awesome. So I can surely say that you should try the Entity Framework Profiler
I just checked and, as for NHProf, there is a free trial version.
You can cast to ObjectQuery and call ToTraceString:
ObjectSet<User> objectSet = ObjectSet;
var query = (ObjectQuery)(objectSet.Where(u => u.LastName == "Doe").Select(u => u));
string trace = query.ToTraceString();
For tracing/caching you can try the EF Caching and Tracing Provider Wrapper. I haven't had a chance to try it yet, but it's definitely on my to do list.

Lightweight ADO.NET Helper Class

Can anyone point me towards a current library that provides basic wrapping of ADO.NET functionality? I'm looking for something along the lines of the old SqlHelper class and am not really interested in using the Data Access Application Block (as it's a bit of overkill for my simple needs). What is everyone using for working with ADO.NET directly these days?
Update:
I should note that I'm already working with an ORM (Nhibernate); I've just run up against a situation that requires raw ADO.NET calls - so no need to suggest using an ORM instead of working with ADO.NET
Dan, this is a class that I have built up over a few years. I use ADO.NET extensivly. It supports simple things like Fill, NonQuery, Scalar, but also getting a schema, transactions, bulk inserts, and more.
DataAdapter (VisualStudio 2010 solution)
Let me know if you need any more help using this (note: I removed some links to other objects to post this for you, so if it's broken, just let me know).
I've written my own little helper library (one .cs file) here:
https://github.com/jhgbrt/yadal/blob/master/Net.Code.ADONet.SingleFile/netstandard/Db.cs
You can find the non-joined version, tests, and readme here:
https://github.com/jhgbrt/yadal
I ended up going with Fluent Ado.net for this; great little library for doing the simple out-of-band ado.net stuff that pops up every now and then.
Hope it helpful:
public static class DbHelper {
public static IDbCommand CreateCommand(this IDbConnection conn, string sql, params object[] args) {
if (!(conn is SqlConnection))
throw new NotSupportedException();
var command = (SqlCommand)conn.CreateCommand();
try {
var paramterNames = new List<string>(args.Length);
for (int i = 0; i < args.Length; i++) {
string name = "#p" + i;
command.Parameters.AddWithValue(name, args[i]);
paramterNames.Add(name);
}
command.CommandText = string.Format(sql, paramterNames.ToArray());
}
catch (Exception) {
if (command != null)
command.Dispose();
throw;
}
return command;
}
}