All posts by Julie Lerman

Announcing: Deep Dive into EF Core 2-Day Workshop

Join me in London June 17-18 for a 2-day deep dive into Entity Framework Core.

This is a new addition to Skills Matter course catalog. Because it is a new course, we are looking to get feedback on the proposed list of topics to be covered. If you are interested in attending, your input will be helpful.

Is the list of topics too long for 2 days? Does it touch on what you would want to learn in an advanced class? You can provide feedback on the course description page.

Day 1: Leverage Advanced Features

  • High level review of EF Core differences from EF6
  • Implementing logging to capture EF Core’s database and in-memory activity. Learn about different types of logging data to be captured
  • Learn various approaches to seeding such as via database scripts, code or using the migration-based seeding introduced in EF Core 2.1. You’ll also learn when each approach may be appropriate
  • Using migrations during development,within source control and during deployments
  • Integration testing your EF Core code

Day 2: EF Core in Your Software Architecture

  • The Great Repository Debate: Pros and Cons of the Repository Pattern/Generic Repositories for exposing EF Core
  • Designing Data Layers/APIs
  • Understanding complicated mapping conventions and supplementing those with custom mappings using the Fluent API
  • Designing for performance
  • *Bonus topic* If all modules have been covered, you will also look at EF Core in Azure Functions and EF Core with Azure Cosmos DB (given adequate time)

A Few Coding Patterns with the MongoDB C# API

In the February 2019 issue of MSDN Magazine (Exploring the Multi-Model Capability of Azure Cosmos DB Using Its API for MongoDB), my Data Points column explored working with the MongoDB model of Azure Cosmos DB using the mongocsharpdriver. I started by working against a local instance of MongoDB and then the Azure instance. But the column was a little bit long so I cut out a few extraneous sections . So I’m placing them here and linking to this blog post from the article.

In the article I used an IMongoCollection object to query and store data into the database. You must specify a type for the collection object to serialize and deserialize. In the article I typed the collection to my classes, e.g.,  Collection<Ship>. It’s also possible to type the collection generically to a BsonDocument. Here’s some information about that and a little bit of code.

Typing Collections to BsonDocument

Another path for mapping is to use a BsonDocument typed collection object that isn’t dependent on a particular type. This would allow you to have more generic methods. But it also means manually serializing and deserializing your objects, which is easy using ToBsonDocument for serializing:

var coll = db.GetCollection<BsonDocument> ("Ships");
coll.InsertOne (ship.ToBsonDocument());

Given that the documents have discriminators, you can then specify a type in your query to retrieve specific types although, by default, hierarchies don’t get accounted for. The article refers to documentation on polymorphism for the C# API. Here’s the link. Check  to learn how to properly implement polymorphism in more detail . The following code will only pull back documents where _t matches the configured discriminator for Ship into ships and for DecommissionedShip into dShips:

var coll = db.GetCollection<BsonDocument> ("Ships");
var ships = coll.AsQueryable().OfType<Ship>().ToList();
var dShips = coll.AsQueryable()
                  .OfType<DecommissionedShip>().ToList();

Encapsulating the MongoClient, Database and Collection

Specifying a typed collection instance repeatedly, as I did in the article demos, can become a drag. You could set them up in advance, for example in a class that acts as a context for interacting with the database, as shown here:

public class ExpanseContext
{
  public IMongoDatabase ExpanseDb { get; private set; }
  public IMongoCollection<Ship> Ships { get; private set; }
  public IMongoCollection<Character> Characters {get;private set;}
  public ExpanseContext()
  {
    ExpanseDb=new MongoClient().GetDatabase("ExpanseDatabase");
    Ships=ExpanseDb.GetCollection<Ship>("ships");
    Characters=ExpanseDb.GetCollection<Character>("ships"); 
  } 
}

This refactored code to insert a document is much more readable:

private static void InsertViaContext ()
{
  var context = new ExpanseContext ();
  var ship = new Ship { Name = "Agatha King" };
  context.Ships.InsertOne (ship);
}

Logging in EF Core 2.2 Has a Simpler Syntax–More like ASP.NET Core

Logging EF Core’s memory operations and SQL operations has evolved a few times since EF Core arrived. It takes advantage of the same underlying features that ASP.NET Core uses. If you are using ASP.NET Core, logging is baked in and it is really simple to turn it on for EF Core and add filtering. See Shawn Wildermuth’s blog post about EF Core logging in ASP.NET Core.

But if you aren’t using ASP.NET Core, it’s a little more complicated. Not terribly, but still there’s some extra work to do. It involves setting up an ILoggerFactory in your DbContext and defining any filters at the same time.

I wrote an article about this (with the focus being on taking advantage of the various available filters for EF Core logging) in MSDN Magazine earlier this …oh wait, it’s Jan 1, so I can say “last  year”.  Data Points – Logging SQL and Change-Tracking Events in EF Core. I also used it heavily in my EF Core 2 Getting Started course, EF Core 2:Mappings and EF Core 2.1: What’s New courses on Pluralsight. (Note that I’ve updated the sample code for the Getting Started course to EF Core 2.2 and put it on GitHub at github.com/julielerman/PluralsightEFCore2GettingStarted)

My article and courses were using Console apps to demonstrate EF Core behavior and therefore the ConsoleLoggerProvider to tie the logger to the console. Note that the Data Points article contains a lot of good details about the various types of filtering. So you can use the new syntax (below) to specify that there should be a filter, but be sure to read the article to learn about the flavors of filtering and what type of details you’ll be able to see based on the choices you make.

But the logging API has continued to evolve and is providing some of the same shortcuts that ASP.NET had created. And the ConsoleLoggerProvider has been deprecated. The API is not part of EF Core. It’s part of .NET Core. Both EF Core and ASP.NET Core use it.

If you are using EF Core 2.2, the syntax has changed (simplified) and it’s going to get even more streamlined in 3.0.

In fact, if you use the earlier syntax with 2.2, you’ll get a warning about the ConsoleLoggerProvider:

Obsolete(“This method is obsolete and will be removed in a future version. The recommended alternative is using LoggerFactory to configure filtering and ConsoleLoggerOptions to configure logging options.”)

For a point of comparison, here is an example of using theold syntax to turn on logging, only show logs related to database commands and only show messages that are tagged as “Information”.

EF Core 2.0 & 2.1 Logic

public static readonly LoggerFactory MyConsoleLoggerFactory
            = new LoggerFactory(new[] {
              new ConsoleLoggerProvider((category, level)
                => category == DbLoggerCategory.Database.Command.Name
               && level == LogLevel.Information, true) });

Once your logger factory field is defined in the context class you tell the DbContext to use it when configuring.

protected override void OnConfiguring
  (DbContextOptionsBuilder optionsBuilder)
{
  var connectionString = 
    ConfigurationManager.ConnectionStrings["WPFDatabase"].ToString();
  optionsBuilder
    .UseLoggerFactory(MyConsoleLoggerFactory)
    .EnableSensitiveDataLogging(true)
    .UseSqlServer(connectionString);
}

So it’s the creation of the logger factory whose syntax is a little convoluded. The newer API follows how ASP.NET Core lets you filter with an AddFilter method that takes the filters as parameters. No lambdas needed. Also configuring the filter is a separate bit of logic that tellig the logger that it should be tied to the console.

EF Core 2.2 Logic

With EF Core 2.2, you can set up the logger factory in the constructor or another method as long as it’s available when you are configuring the option builder. I’m creating it in a method then using that method as a parameter of UseLoggerFactory. I’m still filtering on showing only database commands and log details flagged as Information.

private ILoggerFactory GetLoggerFactory()
{
  IServiceCollection serviceCollection = new ServiceCollection();
  serviceCollection.AddLogging(builder =>
         builder.AddConsole()
                .AddFilter(DbLoggerCategory.Database.Command.Name, 
                           LogLevel.Information)); 
  return serviceCollection.BuildServiceProvider()
          .GetService<ILoggerFactory>();
}

and then I’m calling GetLoggerFactory() in the UseLogging method on the optionsbuilder:

optionsBuilder.UseLoggerFactory(GetLoggerFactory())

Packages and References

In order to use the AddConsole() method, you still have to use the Microsoft.Extensions.Logging.Console package that the earlier ConsoleLoggerProvider was in. However, you do not need a using statement for the namespace (as you did for the ConsoleLoggerProvider).

Getting the SQL Server 2019 for Linux CTP2.0 Docker Image

If you are used to pulling the mssql-server images from the microsoft repository, e.g.,

docker pull microsoft/mssql-server

that won’t work for the 2019 CTP.

I was able to repull (aka update) using the former repository, but that wasn’t working for the CTP whose tag is vNext-CTP2.0-ubuntu.

I finally noticed the new docker pull command on the docker hub page for the image

It says: docker pull mcr.microsoft.com/mssql/server

So the command for pulling the CTP using it’s tag is as follows:

docker pull mcr.microsoft.com/mssql/server:vNext-CTP2.0-ubuntu

 

My First Newsletter: New Course, Pluralsight Discount, Workshops & More

I recently decided it was time to start a newsletter to be sure people who are interested don’t miss out on things like new Pluralsight courses or articles that I’ve published, conferences I’m speaking at and even workshops that I’m teaching. I figure with 26K twitter followers, there might be a few people interested.

Read the June newsletter

Subscribe to my newsletter

I just sent out the first newsletter yesterday. Here are some highlights:

 

 

 

Pluralsight Subscriptions On Sale This Week!

Pluralsight is having a summer sale on annual subscriptions – $100 off (i.e. $199 for an entire year’s access to the entire library) which is a pretty amazing price for what you’re getting. Heck the regular price of $299 for a full year is amazing when you compare it to the cost of almost any type of training from the expert-authors). Anyway, I don’t have to tell you, you already know!

The $199 price is for new subscriptions, renewing  existing subscriptions and even converting from a monthly subscription!

EF Core’s IsConfigured and Logging

I got a little confused about some behavior today and finally realized my mistake so thought I would share it. This mostly happens in demo apps that I’m building that are not using  ASP.NET Core.

In these cases, I typically stick the DbContext provider configuration in the OnModelConfiguring method. For example, if I’m using SQLite, then I would specify that in the method as such:

protected override void OnConfiguring
 (DbContextOptionsBuilder optionsBuilder)
{
   optionsBuilder.UseSqlite (@"Filename=Data/PubsTracker.db");
}

I also have been using the logging factory a lot. After defining it, I also configure it. I hadn’t thought much about where I was placig it so added it in randomly.

protected override void OnConfiguring 
  (DbContextOptionsBuilder optionsBuilder)
{
  optionsBuilder.UseLoggerFactory (MyConsoleLoggerFactory);
  optionsBuilder.UseSqlite (@"Filename=Data/PubsTracker.db");
}

Then I added in some tests to had to avoid the SQLite provider if the InMemory provider was already configured, so I wrapped the UseSqlite method with a check to see if the options builder was already configured.

protected override void OnConfiguring
  (DbContextOptionsBuilder optionsBuilder)
{
  optionsBuilder.UseLoggerFactory (MyConsoleLoggerFactory);
  if(!optionsBuilder.IsConfigured)
  {
    optionsBuilder.UseSqlite (@"Filename=Data/PubsTracker.db");
  }
}

But my logic wasn’t working. I was running some migrations but they were suddenly not recognizing the UseSqlite method. I’ve used this pattern so many times. It took me a while to realize what was going on. The UseLoggerFactory is a configuration!

I just had to move the UseLoggerFactory logic after the IsConfigured check and all was well.

This is one of those dumb things that seems so silly you wouldn’t imagine someone else would make such a mistake. But since it bit me, I thought it was worth sharing mostly for the sake of the next coder who is trying to solve the same problem.

The Secret to Running EF Core 2.0 Migrations from a NET Core or NET Standard Class Library

I have had two people that watched my Pluralsight EF Core Getting Started course (which will soon be joined by an EF Core 2: Getting Started course) ask the same question, which mystified me at first.

The were running migrations commands which caused the project to compile, but the commands did not do anything. For example, add-migration didn’t add a migration file. get-dbcontext did not return any information. The most curious part was there was no error message! I was able to duplicate the problem.

With EF6 it was possible to use migrations from a class library with no exe project in sight. EF Core migrations can run from a .NET Framework or .NET Core project but not .NET Standard. It needs a runtime. A common workaround is that even if you haven’t gotten to the UI part of your app yet, to just add a .NET Core console app project to the solution, add the EF Core Design Nuget package to it and set it as the startup project. But it’s still possible to do this without adding in a dummy project.

We already knew about the multi-targetting fix which solved an error when you try to run migrations from a .NET Standard library. But even with that fix in place, we were getting the mysterious nothingness.

The answer to the question was buried in a GitHub issue and in comments for the Migrations document in the EF Core docs. This same solution solved a problem I was having when trying to use migrations in a UWP app (again, not .NET Core or .NET Framework) that used a separate class library to host its DbContext.

I’m writing this blog post to surface the solution until it is resolved.

The solution that we used with EF Core 1.0 in order to run migrations from a .NET Standard library was to multi-target for .Net Standard (so you can use the library in a few places) and .NET Core (so you can run migrations).

That means replacing

<PropertyGroup>       
  <TargetFramework>netstandard20</TargetFramework>
</PropertyGroup>

with

<PropertyGroup> 
  <TargetFrameworks>netcoreapp2.0;netstandard2.0</TargetFrameworks>
</PropertyGroup>

Notice that the attribute name is now plural and there is a semi-colon between the two SDKs.

But there’s one more secret which is not in the documentation.

For .NET Standard 2.0 (and EF Core 2.0), you also need to add the following to csproj.

<PropertyGroup>
 <GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles></PropertyGroup>

Now with the DbContext project set as the startup and ensuring that the package manager console (or command line) are pointing to the same project, your migration commands will work.

Thanks to Christopher Moffat who found the solution in the GitHub issues and shared it in the comments on the EF Core Package Manager Console Tools document.


Screenshot for Tony ..see my comment in reply to your comment below.