I'm currently working on a WPF project with .NET 5.0 using Catel 5.12.19 and Microsoft.EntityFrameworkCore 5.0.11.
For the EF part I use a code first approach.
When setting up everything using this catel documentation I noticed the necessary extensions are moved to Orc.EntityFramework, but this supports EF 6 and up only.
For EF Core I find Orc.EntityFrameworkCore but only as Alpha versions.
I wondered how stable this is, anyone expercienes?
I'm specifically looking to the .IgnoreCatelProperties() extension
Jeroen
For now it seems sufficient to add the following Ignores to the OnModelCreating
public class Model : DbContext
{
public Model() : base() { }
public Model(DbContextOptions<Model> options) : base(options) { }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
new CustomersEntityTypeConfiguration()
.Configure(modelBuilder.Entity<Customers>()
.Ignore("IsDirty")
.Ignore("IsReadOnly")
);
}
public DbSet<Customers> Customers { get; set; }
}
public class CustomersEntityTypeConfiguration : IEntityTypeConfiguration<Customers>
{
public void Configure(EntityTypeBuilder<Customers> builder)
{
builder
.Property(c => c.ID)
.IsRequired();
}
}
Related
I have an old project developed with the Entity Framwork 4.0 which uses some complex types. Since I need to migrate it to .NET Core, I created a new project, installed all required libraries and used the command
PM> Scaffold-DbContext "Server=ServerInstance; Database=DBName; Trusted_Connection=True;"
Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models
on the existing database in order to create the new models. The problem is that it does not generate the complex type classes.
I can imagine I could replace the generated properties with by hand created complex types, use the [ComplexType] attribute and set the property using OwnsOne command, but I was wandering if there is a sort of auto generation option.
Is there a way to do this?
I created a second partial class in order to add custom stuff to the created one. Added also a partial OnModelCreatingPartial method in which I define my complex types.
Here a snippet:
[Owned]
public class MyComplexType
{
public bool AField { get; set; }
public string BField { get; set; }
}
public partial class MyMainEntity
{
public MyComplexType MyComplexType { get; set; }
}
public partial class MyDbContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer("myConnectionString",
opts => opts.CommandTimeout((int)TimeSpan.FromMinutes(10).TotalSeconds)
);
}
}
partial void OnModelCreatingPartial(ModelBuilder modelBuilder)
{
modelBuilder.Entity<MyMainEntity>().OwnsOne(e => e.MyComplexType, myComplexType =>
{
myComplexType.Property(p => p.AField).HasColumnName("ColumnNameFieldA");
myComplexType.Property(p => p.BField).HasColumnName("ColumnNameFieldB");
});
}
}
I'm trying to change the ID of the Users table from a string (GUID) to an int and really struggling. I have looked at lots of examples but they seem to be for earlier versions of Identity or vs and for numerous reasons they don't work.
I either get a compiler error
'Microsoft.AspNetCore.Identity.IdentityUser', on 'Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserOnlyStore 6[TUser,TContext,TKey,TUserClaim,TUserLogin,TUserToken]' violates the constraint of type 'TUser'.
Or when I create the migration I still get a string column for the ID not an int as I was expecting.
I'm using vs2019. Asp.Net.Core 2.2 and Microsoft.AspNetCore.Identity 2.2
Can anyone help me out, please? Thanks!
First extend the IdenityUser class class as follows so that you can add custom properties:
public class ApplicationUser : IdentityUser<int>
{
}
Then extend the IdentityRole class follows if you use Role in application too. You can keep this safely even you don't want to use it:
public class ApplicationRole : IdentityRole<int>
{
}
Now your ApplicationDbContext should be as follows:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser, ApplicationRole, int>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
}
Now in your ConfigureServices method of the Startup class as follows:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<ApplicationUser, ApplicationRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
}
Job done! Now run a brand new migration and apply it.
#TanvirArjel solution also worked with .NET Core 3.1 in my project with modifications. I had added Identity through scaffolding.
Instead of editing ConfigureServices(), I edited IdentityHostingStartup.cs instead and mofified Configure() inside IdentityHostingStartup.cs:
builder.ConfigureServices((context, services) =>
{
services.AddDbContext(options => options.UseSqlServer(context.Configuration.GetConnectionString("IdentityDbContextConnection")));
services.AddIdentity()
.AddEntityFrameworkStores()
.AddDefaultTokenProviders()
.AddDefaultUI(); //add default razor pages for identity (login, register, etc)
});
Following code generates only single table "CertificateEvent".
How do I achieve TPT inheritance in EF Core 2.0?
public abstract class CertificateEvent {
public int CertificateEventId { get; set; }
}
public class Assignment : CertificateEvent {...}
public class Assessment : CertificateEvent {...}
public class MyDbContext : DbContext
{
public MyDbContext(DbContextOptions<MyDbContext> options) : base(options)
{
}
public DbSet<Assessment> AssessorAssessments { get; set; }
public DbSet<Assignment> AssessorAssignments { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<CertificateEvent>().ToTable(nameof(CertificateEvent));
modelBuilder.Entity<Assessment>().ToTable(nameof(Assessment));
modelBuilder.Entity<Assignment>().ToTable(nameof(Assignment));
}
}
class MyDesignTimeDbContextFactory : IDesignTimeDbContextFactory<MyDbContext>
{
public MyDbContext CreateDbContext(string[] args)
{
var builder = new DbContextOptionsBuilder<MyDbContext>();
builder.UseSqlServer("Server=(local);Database=Test;Trusted_Connection=True;MultipleActiveResultSets=true");
return new MyDbContext(builder.Options);
}
}
I've also tried dotnet ef migrations add Inheritance, but it did not created TPT inheritance in the database
TPT is not in EF Core (yet). See
The feeling from our team is that TPT is generally an anti-pattern and
results in significant performance issues later on. While enabling it
may make some folks "happier" to start with it ultimately just leads
to issues. We are willing to consider it though, so we're leaving this
open and will consider it based on the feedback we get.
https://github.com/aspnet/EntityFrameworkCore/issues/2266
I am trying to create a ModelBuilder within my API and can't seem to add .HasRequired() to my code. I am assuming this is due to the fact that it lives within DBModelBuilder, however, I cannot add that also.
It will only allow me to use ModelBuilder.
Otherwise it throws an error: OnModelCreating(DbModelBuilder): no suitable method found to override
Am I missing something here?
My DbContext looks like so:
public class TicketContext : DbContext
{
public DbSet<Tickets> Tickets { get; set; }
public DbSet<Users> Users { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder) // <-- Not allowing me to add DbModelBuilder here
{
modelBuilder.Entity<Tickets>().HasRequired(t => t.Users);
}
}
Update
I have (as a test) started a new project from scratch. I created a new ASP.NET 5.0 project using a Web API template. Straight away my project doesn't recognize DbModelBuilder. I added reference to EntityFramework.dll and still no good. I then added using System.Data.Entity; and it then accepted DbModelBuilder but still complains that the namespace 'DbModelBuilder' could not be found.
I can't understand how I can have this error upfront on a brand new project?
As soon as I try and add the package Entity Framework from NuGet, I get more errors that version 6.1.3 is not compatible with DNX Core 5.0
I can't seem to find any examples/solutions to any of these errors.
Update 2
I have managed to get DbModelBuilder recognized now by adding the EntityFramework.dll reference to the DNX Core 5.0 Assembly as well as the DNX 4.5.1 assembly, however, now it has thrown even more errors wanting System.Core added and mscorlib. I really can't believe how much trouble it is to create a (what I thought would be simple) Web API project.
You can't just call HasRequired off the model builder - you need to indicate the entity you want to change:
public class MyContext: DbContext
{
public DbSet<Foo> Foos { get; set; }
public DbSet<Bar> Bars { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Foo>().HasRequired(f => f.Bar); // assumes Bar navigation added to Foo
}
}
https://msdn.microsoft.com/en-us/data/jj591617.aspx?f=255&MSPPError=-2147217396
What I like to do is separate out my fluent code like this:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new FooConfig());
}
Now I can create a class with all my mapping for that entity:
public class FooConfig : EntityTypeConfiguration<Foo>
{
public FooConfig()
{
// Primary Key
this.HasKey(t => t.FooId);
// Relationships
this.HasRequired(f => f.Bar).WithMany(b => b.Foos);
}
}
You can specified a Unique Key with Fluent Api:
public class MyContext : DbContext
{
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.HasIndex(u => u.Nickname)
.IsUnique();
}
}
public class User
{
public int UserId { get; set; }
public string Nickname { get; set; }
}
But can you do it with Data Annotations?
Edit
Methods change in EF7 Beta 8:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.Index(u => u.Nickname)
.Unique();
}
I'm afraid create an Index using Data Annotation is not still supported in EF 7. Check this link.
I also tried to find some info related with that subject in the last releases and I couldn't find anything.
EF 7 beta 8 release notes
EF 7 RC1 release notes
I found now a post from one of the EF developers (divega) saying this:
In EF7 we support defining indexes using the fluent API but not an
attribute, at least no yet. The IndexAttribute you are possibly
referring to is something we added to the EF 6.x package at some point
but never really became a standard DataAnnotation.
We don't want to copy the original attribute from EF6 as is because
there are a few things in it that we would like to change. Also,
having it in DataAnnotations directly would likely make more sense
than adding it to the EF7 package.
I should mention though that it is highly unlikely that we will add
IndexAttribute in the EF7 RTM timeframe.
Update 1
Apparently this is a feature that will not be added to EF Core, at least for now.
From EF Core documentation:
Indexes can not be configured using Data Annotations.
But you can do it using Fluent Api:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasIndex(b => b.Url)
.HasName("Index_Url");
}
In the absence of built in support, you can use a custom attribute of your own to annotate model properties and apply in OnModelCreating():
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
foreach (var entity in modelBuilder.Model.GetEntityTypes())
{
foreach (var prop in entity.GetProperties())
{
var index = prop.PropertyInfo.GetCustomAttribute<IndexAttribute>();
if (index != null)
{
entity.AddIndex(prop);
}
}
}
}
With a simple marker attribute class:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class IndexAttribute : Attribute
{
}
Then in your model class, just add the attribute to create a secondary index:
public class User
{
public int UserId { get; set; }
[Index]
public string Nickname { get; set; }
}