Retrieving SQL Generated by Entity Framework Core - c#

I'm trying to retrieve the raw SQL generated by Entity Framework for the following LINQ query:
pagedItemResults = from firstItem in dbData.Accession
join secondItem in pagedRowNumberResults
on firstItem.AccessionNumber equals secondItem
select new PaginationResultRow
{
Number = firstItem.AccessionNumber,
ID = firstItem.AccessionId,
Name = firstItem.AcquisitionType.Name,
Description = firstItem.Description
};
Although it may be extremely simple and similar to the other answers already out there for previous versions of EF, I've had no luck and found nothing online.. any ideas??

You can turn on logging by implementing ILoggerProvider. See details in documentation.
You only need to register the logger with a single context instance. Once you have registered it, it will be used for all other instances of the context in the same AppDomain.
using (var db = new BloggingContext())
{
var serviceProvider = db.GetInfrastructure<IServiceProvider>();
var loggerFactory = serviceProvider.GetService<ILoggerFactory>();
loggerFactory.AddProvider(new MyLoggerProvider());
}
You can also define categories what you want to log.
private static string[] _categories =
{
typeof(Microsoft.Data.Entity.Storage.Internal.RelationalCommandBuilderFactory).FullName,
typeof(Microsoft.Data.Entity.Storage.Internal.SqlServerConnection).FullName
};

You can log tsql generated to output window by :
Microsoft.Extensions.Logging.Debug
First, get it from Nuget, then in your context, you must define a LoggerFactory.
After that, use it in OnConfiguring in your context.
public static readonly Microsoft.Extensions.Logging.LoggerFactory _loggerFactory =
new LoggerFactory(new[] {
new Microsoft.Extensions.Logging.Debug.DebugLoggerProvider()
});
optionsBuilder.UseLoggerFactory(_loggerFactory);

I really like MiniProfiler, see http://miniprofiler.com/. Short of something like this, I would say you'd have to use a profiler on the actual database.

Related

NET MVC Toggle between Seed Data and Real Data

In Net MVC Core 2, Is there a method in Visual Studio, to Toggle between artificial in-memory Seed data, and real Test Environment sql connection? We are continuously testing between two environments.
This is how to create artificial data from source: "Pro ASP.NET Core MVC 2, Freeman".
To Toggle between Seed Data, I have to remove all this, and then add a real connection string again in Application.json, I am trying to prevent removing/adding code. Currently beginner in MVC, only programming for few months, so trying to learn. Thank you
Create seed data
new Product {
Name = "Kayak", Description = "A boat for one person",
Category = "Watersports", Price = 275 },
new Product {
Name = "Lifejacket",
Description = "Protective and fashionable",
Category = "Watersports", Price = 48.95m },
Then in Startup.cs
public void ConfigureServices(...
services.AddTransient<IProductRepository, EFProductRepository>();
public void Configure(...
SeedData.EnsurePopulated(app);
In order to automatically switch connection string, you'd need to use environment-based configurations. Then, based on your environment variable, your app would read different values.
Check this answer for more details: Setting Environment Variables in .net Core 2.0
The feature, you're looking for, is in EF Core. It's .UseInMemoryDatabase option:
public TestDbContext Context => InMemoryContext();
private TestDbContext InMemoryContext()
{
var options = new DbContextOptionsBuilder<TestDbContext>()
.UseInMemoryDatabase(Guid.NewGuid().ToString())
.EnableSensitiveDataLogging()
.Options;
var context = new TestDbContext(options);
return context;
}
This blog would fill the gaps: https://garywoodfine.com/entity-framework-core-memory-testing-database/

Does an equivalent to Database.CompatibleWithModel(bool) exist in EF Core

I'm working on a project that uses EFCore 2.1.0-preview1-final code first approach. Like in EF6 (and previous versions) I want to ensure the compatibility of my DbContext (and models) to the database.
In EF6 it was enabled by default and it was possible to deactivate it with Database.CompatibleWithModel(false);. As far as I know EF uses the __MigrationHistory table where the model information was stored. EFCore has no such column in __EFMigrationsHistory table that could provide such information.
I cannot find any information about compatibility check in EFCore. But I want to ensure the compatibility, because after some tests it seems not to be enabled by default (or does exist). I tested it by adding and deleting some columns from database manually and executing the application after the modifications. I - against my expectation - received no exception.
Does anybody know how to achieve a compatibility check from model to database and vice versa like in EF6 for EFCore?
Or could provide some helpful links for further information about it or why it doesn't exist in EFCore (because it is not necessary)?
I strongly advise against doing this since it uses internal components and is error-prone, but here's one way to do it.
using (var db = new MyDbContext())
{
var reporter = new OperationReporter(handler: null);
var designTimeServiceCollection = new ServiceCollection()
.AddSingleton<IOperationReporter>(reporter)
.AddScaffolding(reporter);
new SqlServerDesignTimeServices().ConfigureDesignTimeServices(designTimeServiceCollection);
var designTimeServices = designTimeServiceCollection.BuildServiceProvider();
var databaseModelFactory = designTimeServices.GetService<IScaffoldingModelFactory>();
var databaseModel = (Model)databaseModelFactory.Create(
db.Database.GetDbConnection().ConnectionString,
tables: new string[0],
schemas: new string[0],
useDatabaseNames: false);
var currentModel = db.Model;
// Fix up the database model. It was never intended to be used like this. ;-)
foreach (var entityType in databaseModel.GetEntityTypes())
{
if (entityType.Relational().Schema == databaseModel.Relational().DefaultSchema)
{
entityType.Relational().Schema = null;
}
}
databaseModel.Relational().DefaultSchema = null;
databaseModel.SqlServer().ValueGenerationStrategy =
currentModel.SqlServer().ValueGenerationStrategy;
// TODO: ...more fix up as needed
var differ = db.GetService<IMigrationsModelDiffer>();
if (differ.HasDifferences(databaseModel, currentModel))
{
throw new Exception("The database and model are out-of-sync!");
}
}

Gridlookupedit Entity Framework

how can i fill the gridlookupedit correctly?.
I can not find the error.
Method fill gridlookupedit
public void CargaGLEVerdadero()
{
pcbjEntidades contexto = new pcbjEntidades();
IList consultaModeloInsumosVerdadera = (from ModeloInsumoes in contexto.ModeloInsumoes
where
ModeloInsumoes.Activo == true
select new
{
ModeloInsumoes.NombreModeloInsumo
}).ToList();
gleNombreModelo.Properties.DataSource = new BindingSource(consultaModeloInsumosVerdadera, "");
}
Construct of form
public frmAgregarMarca()
{
InitializeComponent();
CargaGLEVerdadero();
}
This issue does not related to GridLookup directly rather the to the EF/Winforms interoperation.
Since you are using DevExpress, you can use the Data Source Configuration Wizard.This feature is available for any data-aware control in threir suite and it knows how to do the things correctly and it can make all the work for you:
// This line of code is generated by Data Source Configuration Wizard
// Instantiate a new DBContext
WindowsFormsApplication2.CountriesDBEntities dbContext = new WindowsFormsApplication2.CountriesDBEntities();
// Call the Load method to get the data for the given DbSet from the database.
dbContext.Countries.Load();
// This line of code is generated by Data Source Configuration Wizard
gridLookUpEdit1.Properties.DataSource = dbContext.Countries.Local.ToBindingList();
Then you can customize Wizard's output:
dbContext.Countries.Where(c => c.Capital.StartsWith("A")).Load();

VersionOne API Client not recognizing asset types?

I am running into a problem with the VersionOneAPIClient in that it will not recognize anything I give it ass an asset type. I understand the Attribute definitions probably don't make any sense but I've been trying pretty much everything. My end goal would be to query TeamRooms and get team names from all the teams in the team room.
It's my understanding from the documentation on asset types and how to query that this should work but that's what we all say.
I am using:
C# ASP.NET, VersionOneAPIClient 15.0.0.0
Strings I have tried:
TeamRoom
Task
Scope
Project
public bool APIgetTeams()
{
IAssetType teamroomType = services.Meta.GetAssetType("Task");
Query query = new Query(teamroomType);
IAttributeDefinition teamAttribute = teamroomType.GetAttributeDefinition("Children:Room.Team.Name");
query.Selection.Add(teamAttribute);
IAttributeDefinition scheduleAttribute = teamroomType.GetAttributeDefinition("Children:Scope.Room.Schedule.Name");
query.Selection.Add(scheduleAttribute);
query.Find = new QueryFind(scheduleName, new AttributeSelection(scheduleAttribute));
query.Paging.PageSize = 1;
query.Paging.PageSize = 0;
teamRoomAsset = (Asset)services.Retrieve(query).Assets.ToArray().GetValue(0);
return true;
}
My definition of services and the connector:
public static V1Connector connector = V1Connector
.WithInstanceUrl("http://versionone.cscinfo.com/VersionOneProd/")
.WithUserAgentHeader("New Dashboard?", "1.0")
.WithWindowsIntegrated()
.Build();
public IServices services = new Services(connector);
And these are my Errors / Stack Traces:
The error is likely simple and right in my face but I can't figure it out.
You have a couple of things going on here. I will address your statement "My end goal would be to query TeamRooms and get team names from all the teams in the team room."
Here is a working chunk of code that reads all of your TeamRooms and prints the name of the Team Room and the Team Name. Once you get this working on your machine, attempt to do the paging. Add filtering incrementally to keep the debug cycles low.
static void Main(string[] args)
{
V1Connector connector = V1Connector
.WithInstanceUrl("https://www.MyV1INstance")
.WithUserAgentHeader("HappyApp", "0.1")
.WithUsernameAndPassword("login", "pwd")
.Build();
IServices services = new Services(connector);
IAssetType trType = services.Meta.GetAssetType("TeamRoom");
Query query = new Query(trType);
IAttributeDefinition teamAttribute = trType.GetAttributeDefinition("Team.Name");
IAttributeDefinition nameAttribute = trType.GetAttributeDefinition("Name");
query.Selection.Add(teamAttribute);
query.Selection.Add(nameAttribute);
QueryResult result = services.Retrieve(query);
Asset teamRooms = result.Assets[0];
foreach (Asset story in result.Assets)
{
Console.WriteLine(story.Oid.Token);
Console.WriteLine(story.GetAttribute(teamAttribute).Value);
Console.WriteLine(story.GetAttribute(nameAttribute).Value);
Console.WriteLine();
}
Addendum
I just realized that you were using WithWindowsIntegrated() instead of WithUsernameAndPassword().
Just change that in my sample but then confirm that you are logged into the machine as a Member that is already setup in VersionOne. The windows int auth is trusting IIS' decision to trust you but then immediately after allowing auth, you have to have an active Member account in VersionOne to have access to VersionOne assets.

Saving an entity to the DB in WinForms

I've looked at so many posts about this, but still haven't found the solution:
I'm using a winforms app that uses EntityFramework (6?). When I load the form I can read from the DB using the context (Entities). However, when I savechanges after adding a new entity, it doesn't persist to the db.
var c = new Card { Name = tbName.Text, Quantity = int.Parse(tbQuantity.Text) };
dbContext.Cards.Add(c);
dbContext.SaveChanges();
The dbContext is setup in the form constructor and is an instance of "LiquorTrackEntities".
LiquorTrackEntities dbContext;
public Form1()
{
InitializeComponent();
dbContext = new LiquorTrackEntities()
Reading from the db works:
var cards = dbContext.Cards.ToList();
I do this stuff all the time in asp.net MVC, but it isn't working in WinForms.. is there something special I have to do in winforms? I also know about the normal "using (var db = new LiquorEntitiesEntities())" convention, but I just want to get this functioning before I worry about convention.
Any ideas?
Just tried this to no avail:
var c = new Card { Name = tbName.Text, Quantity = int.Parse(tbQuantity.Text) };
dbContext.Cards.Attach(c);
dbContext.Entry(c).State = EntityState.Added;
dbContext.SaveChanges();
Just tried creating a new EDMX using EF5 instead.. same problem.
UPDATE:
SaveChanges does return a 1 when after adding a card. It stays in the context (if I reload my cards from the context, the new one is there..) but never makes it to the database.

Categories