Returning the error message above in a new asp.net core 3.1 project. I have a many-to-many relationship configured according to Text
Not exactly sure why this would be happening but I have added the EntityFrameworkCore package to the project so I'm not sure why it's returning this error.
DBContext.cs:
using Microsoft.EntityFrameworkCore;
using Ballista.Models;
namespace Ballista.Data
{
public class AnnouncementsContext : DbContext
{
public AnnouncementsContext (DbContextOptions<AnnouncementsContext> options)
: base(options)
{
}
public DbSet<Announcements> Announcements { get; set; }
public DbSet<AnnouncementTargets> AnnouncementTargets { get; set; }
public DbSet<TargetGroup> TargetGroup { get; set; }
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<AnnouncementTargets>()
.HasKey(at => new { at.AnnouncementID, at.TargetGroupID });
modelBuilder.Entity<AnnouncementTargets>()
.HasOne(at => at.Announcement)
.WithMany(a => a.AnnouncementTargets)
.HasForeignKey(at => at.AnnouncementID);
modelBuilder.Entity<AnnouncementTargets>()
.HasOne(at => at.TargetGroup)
.WithMany(tg => tg.AnnouncementTargets)
.HasForeignKey(t => t.TargetGroupID);
base.OnModelCreating(modelBuilder);
}
}
AnnouncementModels.cs:
using System;
using System.ComponentModel.DataAnnotations;
using System.Collections.Generic;
namespace Ballista.Models
{
public class Announcements
{
public int ID { get; set; }
public string Title { get; set; }
public string SubTitle { get; set; }
public string Content { get; set; }
public ICollection<AnnouncementTargets> AnnouncementTargets { get; set; }
}
public class TargetGroup
{
public int ID { get; set; }
public string Group { get; set; }
public ICollection<AnnouncementTargets> AnnouncementTargets { get; set; }
}
public class AnnouncementTargets
{
public int AnnouncementID { get; set; }
public Announcements Announcement { get; set; }
public int TargetGroupID { get; set; }
public TargetGroup TargetGroup { get; set; }
}
}
I have a many-to-many relationship configured but I keep getting the error message <invalid-global-code>.OnModelCreating(ModelBuilder)': no suitable method found to override
DbContext have OnModelCreating(DbModelBuilder) to override.
Change definition of function from OnModelCreating(ModelBuilder modelBuilder) to OnModelCreating(DbModelBuilder modelBuilder)
protected override void OnModelCreating(DbModelBuilder modelBuilder)
Related
I have a project that is running with .net core 6, EF Core 6.0.9, DB -> postgresql 14.
I have these classes
public class Language
{
[Key]
public long Id { get; set; }
public string PublicId { get; set; }
public string Name { get; set; }
public virtual ICollection<Course> CoursesFrom { get; set; }
public virtual ICollection<Course> CoursesTo { get; set; }
}
public class Course
{
[Key]
public long Id { get; set; }
public string PublicId { get; set; }
public string Name { get; set; }
public virtual Language LanguageFrom { get; set; }
public virtual Language LanguageTo { get; set; }
}
The relation is defined as follows:
public class LanguageConfiguration : IEntityTypeConfiguration<Language>
{
public void Configure(EntityTypeBuilder<Language> builder)
{
...
builder.HasMany(l => l.CoursesFrom)
.WithOne(c => c.LanguageFrom);
builder.HasMany(l => l.CoursesTo)
.WithOne(c => c.LanguageTo);
}
}
public class CourseConfiguration : IEntityTypeConfiguration<Course>
{
public void Configure(EntityTypeBuilder<Course> builder)
{
...
builder.HasOne(l => l.LanguageFrom)
.WithMany(c => c.CoursesFrom)
.OnDelete(DeleteBehavior.SetNull);
builder.HasOne(l => l.LanguageTo)
.WithMany(c => c.CoursesTo)
.OnDelete(DeleteBehavior.SetNull);
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfiguration(new LanguageConfiguration());
modelBuilder.ApplyConfiguration(new CourseConfiguration());
}
And LINQ expression
var query = Context.Course
.Include(l => l.LanguageFrom)
.Include(l => l.LanguageTo)
.ToList();
Main entity is returned but fields LanguageFrom and LanguageTo are null - the Include() does nothing. What am I doing wrong?
When there are multiple navigation properties defined between two types shadow navigation properties do not work. You should define two fields to serve as foreign key in the Course entity:
public class Course
{
[Key]
public long Id { get; set; }
public string PublicId { get; set; }
public string Name { get; set; }
public long LanguageFromId { get; set; }
public long LanguageToId { get; set; }
public virtual Language LanguageFrom { get; set; }
public virtual Language LanguageTo { get; set; }
}
Then
public class CourseConfiguration : IEntityTypeConfiguration<Course>
{
public void Configure(EntityTypeBuilder<Course> builder)
{
...
builder.HasOne(l => l.LanguageFrom)
.WithMany(c => c.CoursesFrom)
.HasForeignKey("LanguageFromId")
.OnDelete(DeleteBehavior.SetNull);
builder.HasOne(l => l.LanguageTo)
.WithMany(c => c.CoursesTo)
.HasForeignKey("LanguageToId")
.OnDelete(DeleteBehavior.SetNull);
}
}
I want to create a one-to-many relationship using EF 6 using a code-first approach.
Let's take simple and classical example. I have two entities Invoice and UserApplication which have a one-to-many relationship:
I also want to have an UpdatedById relationship with the same ApplicationUser table, to be able to show the names in the UI of who added the record and who modified it.
public partial class ApplicationUser : IdentityUser
{
public string FirstName { get; set; };
public string LastName { get; set; };
}
public virtual List<Invoice> Invoices { get; set; }
public class Invoice
{
public int Id { get; set; }
public string Details { get; set; }
public string CreatedById { get; set; }
public string UpdatedById { get; set; }
}
public virtual ApplicationUser CreatedBy { get; set; }
builder.Entity<Invoice>()
.HasOne(f => f.CreatedBy)
.WithMany(mu => mu.Invoices)
.HasForeignKey(f => f.CreatedById);
If you want Navigation Properties on Application user for these relationships, you would need to create and configure seperate ones.
eg
using Microsoft.EntityFrameworkCore;
using System.Linq;
using System;
using System.Collections.Generic;
namespace EfCore6Test
{
public partial class ApplicationUser //: IdentityUser
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public virtual ICollection<Invoice> InvoicesCreated { get; } = new HashSet<Invoice>();
public virtual ICollection<Invoice> InvoicesLastUpdated { get; } = new HashSet<Invoice>();
}
public class Invoice
{
public int Id { get; set; }
public string Details { get; set; }
public int CreatedById { get; set; }
public int UpdatedById { get; set; }
public virtual ApplicationUser CreatedBy { get; set; }
public virtual ApplicationUser LastUpdatdBy { get; set; }
}
public class Db: DbContext
{
public DbSet<Invoice> Invoices{ get; set; }
public DbSet<ApplicationUser> Users{ get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Invoice>()
.HasOne(f => f.CreatedBy)
.WithMany(mu => mu.InvoicesCreated)
.HasForeignKey(f => f.CreatedById)
.OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<Invoice>()
.HasOne(f => f.LastUpdatdBy)
.WithMany(mu => mu.InvoicesLastUpdated)
.HasForeignKey(f => f.UpdatedById)
.OnDelete(DeleteBehavior.Restrict);
base.OnModelCreating(modelBuilder);
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Server=localhost;database=efCore6Test;Integrated Security=true;TrustServerCertificate=true", o => o.UseRelationalNulls(true))
.LogTo(Console.WriteLine, Microsoft.Extensions.Logging.LogLevel.Information);
base.OnConfiguring(optionsBuilder);
}
}
class Program
{
static void Main(string[] args)
{
{
using var db = new Db();
db.Database.EnsureDeleted();
db.Database.EnsureCreated();
}
}
}
}
Or simply omit the Navigation Properties on Application User.
I'm facing issues with Migrations when I use the same class as owned type in different entities.
If I generate an initial migration with the following code, it works properly, but when I try to generate a second one, it throws the error: The entity type 'OwnedTypesTests.AddressDetails' cannot be added to the model because a weak entity type with the same name already exists.
EF Core version 2.2.6
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
namespace OwnedTypesTests
{
public class Program
{
static async Task Main(string[] args)
{
var dbOptions = new DbContextOptionsBuilder<TestDbContext>().UseSqlServer(TestDbContext.ConnectionString).EnableSensitiveDataLogging().EnableDetailedErrors().Options;
using (var dbContext = new TestDbContext(dbOptions))
{
dbContext.Database.EnsureCreated();
Console.WriteLine("Test");
}
}
}
public class TestDbContext : DbContext
{
public const string ConnectionString = "-";
public DbSet<PersonType1> PersonType1s { get; set; }
public DbSet<PersonType2> PersonType2s { get; set; }
public TestDbContext(DbContextOptions<TestDbContext> options) : base(options) {}
public TestDbContext(){}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
var pType1Builder1 = modelBuilder.Entity<PersonType1>();
pType1Builder1.ToTable("person_type_1");
pType1Builder1.HasKey(p => p.Id);
pType1Builder1.OwnsOne(p => p.Address, c =>
{
c.ToTable("Address1");
c.Property<int>("Id");
c.HasKey("Id");
c.Property(a => a.Street).HasColumnName("street_name");
c.OwnsMany(a => a.ListOfDetails, a2 =>
{
a2.ToTable("list_details_1");
a2.HasForeignKey("address1_id");
a2.Property<long>("id");
a2.HasKey("id");
a2.OwnsOne(l => l.From).Property(p => p.Code).HasColumnName("from_code");
a2.OwnsOne(l => l.To).Property(p => p.Code).HasColumnName("to_code");
});
});
var pType1Builder2 = modelBuilder.Entity<PersonType2>();
pType1Builder2.ToTable("person_type_2");
pType1Builder2.HasKey(p => p.Id);
pType1Builder2.OwnsOne(p => p.Address, c =>
{
c.ToTable("Address2");
c.Property<int>("Id");
c.HasKey("Id");
c.Property(a => a.Street).HasColumnName("street_name");
c.OwnsMany(a => a.ListOfDetails, a2 =>
{
a2.ToTable("list_details_2");
a2.HasForeignKey("address2_id");
a2.Property<long>("id");
a2.HasKey("id");
a2.OwnsOne(l => l.From).Property(p => p.Code).HasColumnName("from_code");
a2.OwnsOne(l => l.To).Property(p => p.Code).HasColumnName("to_code");
});
});
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(ConnectionString).EnableSensitiveDataLogging();
}
}
public class PersonType1
{
public int Id { get; set; }
public string Name { get; set; }
public Address Address { get; set; }
}
public class PersonType2
{
public int Id { get; set; }
public string Name { get; set; }
public Address Address { get; set; }
}
public class Address1
{
public string Street { get; set; }
public List<AddressDetails> ListOfDetails { get; set; }
}
public class Address
{
public string Street { get; set; }
public List<AddressDetails> ListOfDetails { get; set; }
}
public class AddressDetails
{
public Location From { get; set; }
public Location To { get; set; }
}
public class Location
{
public string Code { get; set; }
}
}
After upgrading ef-core from version 2.1 to version 2.2 (2.2.2) I started getting an error, when I do a migration.
I created a test project, here is my code:
public class Root
{
public int Id { get; set; }
public MainAddress Address1 { get; set; }
public MainAddress Address2 { get; set; }
}
public class MainAddress
{
public int Id { get; set; }
public string Name { get; set; }
public SubAddress SubAddress { get; set; }
}
public class SubAddress
{
public int Id { get; set; }
public string Name { get; set; }
public int Number { get; set; }
public SubSubAddress SubSubAddress { get; set; }
}
public class SubSubAddress
{
public int Id { get; set; }
public string Text { get; set; }
}
public class RootConfig : IEntityTypeConfiguration<Root>
{
public void Configure(EntityTypeBuilder<Root> builder)
{
builder.ToTable("Roots");
builder.HasKey(it => it.Id);
builder.OwnsOne(root => root.Address1, address =>
{
address.OwnsOne(a => a.SubAddress, subAddress =>
{
subAddress.OwnsOne(it => it.SubSubAddress);
});
});
builder.OwnsOne(root => root.Address2, address =>
{
address.OwnsOne(a => a.SubAddress, subAddress =>
{
subAddress.OwnsOne(it => it.SubSubAddress);
});
});
}
}
public class TestContext : DbContext
{
public TestContext(DbContextOptions<TestContext> context) : base(context)
{
}
public DbSet<Root> Roots { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfiguration(new RootConfig());
}
}
so, when I do update database I getting error:
System.InvalidOperationException: The entity type 'EFError1.Models.SubAddress' cannot be added to the model because a weak entity type with the same name already exists.
If I use the OwnsOne 2 times nested - then all is well.
Any idea?
I'm new to code first and derived from DB Context. Here is a excerpt of my Model.
[Table("pm_Material")]
public class Material
{
public Material()
{
this.ProductionStepLogs = new HashSet<ProductionStepLog>();
}
[Key]
public int MaterialId { get; set; }
public int MaterialTypeId { get; set; }
public string Description { get; set; }
public decimal CostRate { get; set; }
public virtual MaterialType MaterialType { get; set; }
public virtual ICollection<ProductionStepLog> ProductionStepLogs { get; set; }
}
[Table("pm_ProductionStepLog")]
public class ProductionStepLog
{
public ProductionStepLog()
{
this.Materials = new HashSet<Material>();
}
[Key]
public System.Guid ProductionStepLogId { get; set; }
public int ProductionStepId { get; set; }
public System.Guid ProductId { get; set; }
public Nullable<System.DateTime> BeginStep { get; set; }
public Nullable<System.DateTime> EndStep { get; set; }
public int UserId { get; set; }
public virtual Product Product { get; set; }
public virtual ProductionStep ProductionStep { get; set; }
public virtual ICollection<Material> Materials { get; set; }
}
The DB creation works fine, but I want to specify the name of the auto-generated many-to-many table "ProductionStepLogMaterials" using [Table("pm_ProductionStepLogMaterials")].
Is this possible?
You should override your protected override void OnModelCreating(DbModelBuilder modelBuilder) of your own DBContext class like this:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Material>()
.HasMany(a => a.ProductionStepLog)
.WithMany(a => a.Material)
.Map(x =>
{
x.ToTable("NameOfYourTable");
x.MapLeftKey("MaterialId");
x.MapRightKey("ProductionStepLogId");
});
}
AFAIK, this is impossible with Data Annotations, but it is possible with configuration fluent API:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<E1Type>()
.HasMany(e1 => e1.Collection)
.WithMany(e2 => e2.Collection)
.Map(config => config.ToTable("MyTable"));
}