Support for EF Core 5.0, .NET 5.0, and More Features in Entity Developer 6.8

June 18th, 2020

Devart is glad to announce the release of Entity Developer 6.8 – a visual ORM designer for a wide variety of ORMs. The new version introduces support for preview versions of Entity Framework Core 5.0 and .NET 5.0, adds ability to generate C# 8 nullable reference types and configure collection navigation properties, improves support for stored procedures, for NuGet and third-party providers, and many more.

EF Core 5 and .NET 5 Are Coming

EF Core 5 – is a new and actively developed Entity Framework Core version, which already contains a number of improvements and additions (see What’s New in EF Core 5.0 for more details) . EF Core 5 development goes hand-in-hand with that of .NET 5 – the next step of .NET Core evolution and uniting .NET platforms. .NET 5 will support Windows, Linux, macOS, iOS, Android, tvOS, watchOS and WebAssembly. The release of EF Core 5 and .NET 5 is planned to November, 2020, but you can already try the preview versions loaded with new features.

EF Core 5 will not run on .NET Framework. Currently, as of EF Core 5 Preview 5, it supports .NET Standard 2.1 and .NET Core 3.x as well as .NET 5.

The new version of Entity Developer supports EF Core 5 and .NET 5 as of EF Core 5 Preview 5. When new EF Core 5 versions are available, we will update its support in Entity Developer. Please note, however, that EF Core 5 support for .NET Standard 2.1 and .NET Core 3.x is fully implemented in all Entity Developer versions (Visual Studio 2019 add-in, standalone application, and console application). However, as for target framework .NET 5 for EF Core 5 model, we don’t recommend using Visual Studio-integrated Entity Developer. It’s better to use standalone or console Entity Developer.

C# 8 Nullable Reference Types

C# 8, which can be used for .NET Standard 2.1 and .NET Core 3.0/3.1 projects, has a hugely important feature – Nullable Reference Types.

We have supported Nullable Reference Types in Entity Developer in templates for EF Core, Entity Framework 6, and NHibernate. They now have the Nullable Reference Types property that specifies when С# 8 nullable reference types and non-nullable reference types must be generated.

  • If it is set to Enable, then nullable annotation context is enabled.
  • If it is set to Disable, then ‘#nullable disable’ directives are generated.
  • If it is set to Default, then pre-C# 8.0 classic behavior is used.

For example, if there is the following table in SQL Server:

 CREATE TABLE dbo.Categories (
   CategoryID INT IDENTITY PRIMARY KEY,
   CategoryName NVARCHAR(15) NOT NULL,
   Description NVARCHAR(MAX) NULL,
   Picture VARBINARY(MAX) NULL
 ) 

Here is the traditional code, generated for it (a bit simplified):

 public class Category {
       public int CategoryID { get; set; }
       public string CategoryName { get; set; }
       public string Description { get; set; }
       public byte[] Picture { get; set; }
 } 

With Nullable Reference Types = Enable, we will get the following code:

 public class Category {
       public int CategoryID { get; set; }
       public string CategoryName { get; set; }
       public string? Description { get; set; }
       public byte[]? Picture { get; set; }
 } 

Collection Navigation Properties

Entity Developer 6.8 implements an ability to select a collection type for navigation properties, and which non-abstract type to use for property initialization (or don’t perform it at all). This feature is implemented for Entity Framework and Entity Framework Core with the template properties Collection Property Type and Collection Initialization Type.

Collection Property Type accepts the following values for Entity Framework:

  • Default
  • HashSet
  • ICollection
  • IList
  • ISet
  • List

For EF Core, it accepts the following values:

  • Default
  • HashSet
  • ICollection
  • IEnumerable
  • IList
  • IReadOnlyCollection
  • IReadOnlyList
  • ISet
  • List

Collection Initialization Type accepts the following values (for both Entity Framework and Entity Framework Core):

  • Default
  • HashSet
  • List
  • None

Thus, you will get the following code if you set Collection Property Type = ICollection and Collection Initialization Type = List:

 public partial class Category {
 
     public Category()
     {
         this.Products = new List<Product>();
     }
     public virtual ICollection<Product> Products { get; set; }
 } 

And if you set Collection Property Type = ICollection and Collection Initialization Type = None, you will get the following code:

 public partial class Category {

     public Category()
     {
     }

     public virtual ICollection<Product> Products { get; set; }
} 

DEFAULT Column Values

DEFAULT column values support have been available in Entity Developer for a long time, but it wasn’t flexible enough and didn’t allow customization. Suppose we have the following SQL Server table:

CREATE TABLE dbo.DefaultValues (
  Id INT IDENTITY PRIMARY KEY,
  f_nvarchar NVARCHAR(100) NULL DEFAULT 'abc',
  f_int INT NULL DEFAULT 101,
  f_date [date] NULL DEFAULT GETUTCDATE(),
  f_datetimeoffset DATETIMEOFFSET NULL DEFAULT SYSDATETIMEOFFSET(),
  f_guid UNIQUEIDENTIFIER DEFAULT NEWID()
)

Previous Entity Developer versions generate the following code for it:

 public class DefaultValue {
    
     public DefaultValue()
     {
         this.FNvarchar = @"abc";
         this.FInt = 1;
         this.FDate = DateTime.UtcNow;
         this.FDatetimeoffset = DateTimeOffset.Now;
         this.FGuid = new Guid();
     }

     public int Id { get; set; }
     public string FNvarchar { get; set; }
     public int? FInt { get; set; }
     public DateTime? FDate { get; set; }
     public DateTimeOffset? FDatetimeoffset { get; set; }
     public Guid? FGuid { get; set; }
} 

This approach has both pros and cons. Supporters consider that .NET class behavior must be as close as possible to the behavior of a record in the database table or view. Opponents think that default values are unnecessary or even harmful or it should be allowed only for literals and not for expressions.

In order to allow users to decide, we have added a new Primitive Default Value Generation property to templates for Entity Framework, EF Core, NHibernate and Telerik Data Access ORMs. It accepts the following values: None, Literal, LiteralOrExpression. The behavior of previous Entity Developer versions corresponds to the LiteralOrExpression value, and it won’t change for old models. However, we have changed the behavior for new models, and they will have the compromise Primitive Default Value Generation = Literal mode, which adds default value generation in the constructor only for literal constant default values:

 public class DefaultValue {
    
     public DefaultValue()
     {
         this.FNvarchar = @"abc";
         this.FInt = 1;
     }

     public int Id { get; set; }
     public string FNvarchar { get; set; }
     public int? FInt { get; set; }
     public DateTime? FDate { get; set; }
     public DateTimeOffset? FDatetimeoffset { get; set; }
     public Guid? FGuid { get; set; }
} 

If you want to completely turn off setting default values in the code, set Primitive Default Value Generation = None.

Stored Procedure Result Sets and Complex Types

Stored procedures in Console Entity Developer

For many years, only two program versions of Entity Developer have existed: Entity Developer, integrated into Visual Studio and standalone Entity Developer application. The recently released Entity Developer 6.7 has included the third version — a console application. Expanding the capabilities of the new version 6.8, we have implemented support of stored procedures and functions import, as well as a number of fixes for existing functionality.

And now, the console Entity Developer supports import for stored procedures and functions by default. That means if you execute the following command:

ed Create-Model --Provider System.Data.SqlClient --Connection "Data Source=mssqlserver;User Id=sa;database=northwind;" --Templates "EF Core C#" --Schemas dbo --ModelFile "d:\Project\Model.efml"

then not only tables and views will be imported, but also stored procedures and functions.

You can specify a list of stored procedures and functions, which you need to import into the model using such options as ‐‐Procedures and ‐‐Functions:

ed Create-Model --Provider System.Data.SqlClient --Connection "Data Source=mssqlserver;User Id=sa;database=northwind;" --Templates "EF Core C#" --Schemas dbo --ModelFile "d:\Project\Model.efml" --Procedures CustOrderHist,SalesByCategory --Functions ufnGetAccountingEndDate

The only thing the standalone and VS-integrated versions differ from the console Entity Developer version is that stored procedures and functions of standalone and VS-integrated Entity Developer versions are not executed by default. It is because the user has an opportunity to see the list of stored procedures and functions in the graphical interface of Create Model Wizard and make an informed decision whether to import them into the model or not, whether to enable or disable part of them. The console Entity Developer does not display lists of available objects that can be imported into the model. That is why we have added the ‐‐Execute option to Create-Model, which allows you to customize the behavior even in a more flexible way compared to the UI in standalone/ VS-integrated Entity Developer. For example, you can refuse from executing the stored procedures at all or you can execute all stored procedures or you can execute only those specified in the list. The execution of the stored procedures is a must if we want to get information about the returned result sets, build complex types based on these sets, and add them to the model.

To execute all stored procedures:

ed Create-Model --Provider System.Data.SqlClient --Connection "Data Source=mssqlserver;User Id=sa;database=northwind;" --Templates "EF Core C#" --Schemas dbo --ModelFile "d:\Project\Model.efml" --Execute *

To execute only two specified stored procedures:

ed Create-Model --Provider System.Data.SqlClient --Connection "Data Source=mssqlserver;User Id=sa;database=northwind;" --Templates "EF Core C#" --Schemas dbo --ModelFile "d:\Project\Model.efml" --Execute CustOrderHist,SalesByCategory

Stored Procedures in Standalone/VS-integrated Entity Developer

Let us consider further the topic of import for stored procedures and functions, but now for the GUI in the standalone/VS-integrated Entity Developer. When dragging a stored procedure from the Database Explorer to a diagram, Entity Developer users used to get two dialog boxes. The first one displayed a notification that the procedure execution is necessary for obtaining metadata of procedure result sets and a warning on the possibility of database damage. The second dialog box asked users to set parameters. Now, the behavior of dialog boxes has been changed. From now on, if the stored procedure does not have Input parameters, we show only the warning on the procedure execution. If the stored procedure has Input parameters, we show only the dialog box where users can set parameters. This is done for all ORMs.

In Update Model From Database Wizard, you could always choose whether or not to add new entities to the diagram (Add new entity types to the current diagram check box on the last wizard page that is enabled by default). But there was no possibility to add the generated complex types. That is why we have added a new check box – Add new complex types to the current diagram.

We have also implemented a number of new options on the import of stored procedure in the Model Settings EF Core. So far, we have done it only for EF Core, and in the future, according to users’ feedback, this functionality can be either updated or expanded to other ORMs:

  • New option Execute procedures for result set detection is added to control obtaining metadata of a procedure or function result set.
  • New option Use NULL parameter values is added to specify whether NULL parameter values ​​are used for stored procedure execution.
  • New option Add complex types to diagram is added to control behavior of Create Model Wizard and Update Model From Database Wizard.

The first two options influence the behavior of Database Explorer, Create Model Wizard and Update Model From Database Wizard and allow you both to unify the behavior and disable confirmations during the execution of stored procedures when working with Database Explorer.

NuGet and Third-party Providers

In the previous version, Entity Developer 6.7, we have improved support of a number of third-party providers and made standalone Entity Developer able to use provider assemblies and their dependencies from the NuGet cache. We have continued to work on this support, and the new Entity Developer 6.8 has significant improvements for System.Data.SQLite and FirebirdSql.Data.FirebirdClient providers for EF6 and NHibernate models as well as for Microsoft.Data.Sqlite for EF Core models.

Conclusion

This is not a complete list of Entity Developer 6.8 improvements. You can find a complete revision history here. Most of changes and improvements were added based on your feedback. Some were added soon after your suggestions, and some had to wait for significant time, and we are sorry for that. Please share your experience of designing models with Entity Developer and your suggestions about its improvements and new features with us.

Leave a Comment