Empty Migrations are generated in code first ASP.NET MVC - c#

I have been trying to generate migration but some reason, generated migrations is empty except the basic definition of function up and down but empty inside.
Model class
public class StoryDB
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid id { get; set; }
[Required]
public string StoryContent { get; set; }
private int heartsCount { get; set; }
private int commentsCount { get; set; }
private int shareCount { get; set; }
public DateTime dateCreated { get; set; }
public DateTime dateModified { get; set; }
}
Database Context class
public class StoreDB : DbContext
{
public StoreDB() : base("DefaultConnection")
{
}
public virtual DbSet <StoryDB> Stories { get; set; }
}
Note that I am using the same connection DefaultConnection which is used to by Identity Classes
When I generate the initial seeding class that generates perfectly (i.e. all user tables like roles and users)
However when i try to generate the first migration after seed class, then nothing appears in the class

You have to tell the DbContext which entities you want to map to the DB. In your case StoryDB:
public class StoreDB : DbContext
{
public StoreDB() : base("DefaultConnection")
{
}
public virtual DbSet<StoryDB> Stories { get; set; }
}
Note that DbSet has a generic parameter, which tells EF the actual type to use.

Related

EF Core Table-Per-Hierarchy for class with generic

In EF Core 3.1.15 I manage a model with a generic. I would like to store the entities in the same table basis Table-Per-Hierarchy approach (TPH pattern). Below is the model abstracted. The resulting database creates 1 table for Part and descendants with a discriminator (as expected), but instead of 1 table for BaseComputer and descendants it creates a separate table for Computers and a separate table for Laptops (not expected).
namespace EFGetStarted
{
public class BloggingContext : DbContext
{
public DbSet<Computer> Computers { get; set; }
public DbSet<Laptop> Laptops { get; set; }
public DbSet<Part> Parts { get; set; }
}
public abstract class BaseComputer<T> where T : Part
{
[Key]
public int Id { get; set; }
public List<T> Parts { get; set; }
}
public class Computer : BaseComputer<Part>
{
public string ComputerSpecificProperty { get; set; }
}
public class Laptop : BaseComputer<LaptopPart>
{
public string LaptopSpecificProperty { get; set; }
}
public class Part
{
[Key]
public int Id { get; set; }
public string PartName { get; set; }
}
public class LaptopPart : Part
{
public string LaptopSpecificPartProperty { get; set; }
}
}
I tried explicitly specifying the entity as TPH:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<BaseComputer<Part>>()
.HasDiscriminator()
.HasValue<Computer>("Computer")
.HasValue<Laptop>("Laptop");
}
But this fails with the following message:
The entity type 'Laptop' cannot inherit from 'BaseComputer' because 'Laptop' is not a descendant of 'BaseComputer'.
Questions: Is it possible for me to design this model in a TPH pattern? If not, is it because "Laptop is not a descendant of BaseComputer<Part>"? And if that's the case, why is not a considered a descendant and what should I change in the class to make it a descendant?

EnsureCreated method cannot create new tables in db

I'm using context.Database.EnsureCreated(); to map and create automatically tables considering their entities on Mac OS. But, it doesn't create new tables for new entities newly created.
When I run the following codes, I see 3 tables in the db. But when I add Battle.cs and uncomment -
public DbSet<Battle> Battles { get; set; }
in DbContext, the context.Database.EnsureCreated(); call doesn't create the Battle table in database.
Models -
public class Samurai
{
public Samurai()
{
Quotes = new List<Quote>();
}
public int Id { get; set; }
public string Name { get; set; }
public List<Quote> Quotes { get; set; }
public Clan Clan { get; set; }
}
public class Clan
{
public int Id { get; set; }
public string ClanName { get; set; }
}
public class Quote
{
public int Id { get; set; }
public string Text { get; set; }
public Samurai Samurai { get; set; }
public int SamuraiId { get; set; }
}
DbContext -
public class SamuraiContext : DbContext
{
public DbSet<Samurai> Samurais { get; set; }
public DbSet<Quote> Quotes { get; set; }
public DbSet<Clan> Clans { get; set; }
// public DbSet<Battle> Battles { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseMySQL(#"Server=localhost;port=3306;Database=exercise;Uid=root;Pwd=password;allowPublicKeyRetrieval=true;");
base.OnConfiguring(optionsBuilder);
}
}
The Battle model -
public class Battle
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime StartDate { get; set;}
public DateTime EndDate { get; set; }
}
Program -
class Program
{
private static SamuraiContext context = new SamuraiContext();
static void Main(string[] args)
{
context.Database.EnsureCreated();
}
}
As Jeremy commented, EnsureCreated() simply doesn't do what you want to do. From the documentation page:
Ensures that the database for the context exists. If it exists, no
action is taken. If it does not exist then the database and all its
schema are created. If the database exists, then no effort is made to
ensure it is compatible with the model for this context.
EnsureCreated() is great if for example you're integration testing on an in-memory SQLite database.
Normally you want to generate a schema for the current model by running dotnet ef migrations add <MigrationName>, and then if you want to programmatically ensure that the database reflects the current schema, call database.Migrate(). Of course you can also call dotnet ef database update from the cli.
That said, if you're working with a throwaway database of some sorts, and you don't want to bother at all with generating schema or migrations, then ...
database.EnsureDeleted();
database.EnsureCreated();
... should work fine, because these Ensure* methods don't rely on migrations.
(I just tested it by adding an extra entity to a DbContext, then calling EnsureDeleted() followed by EnsureCreated() without a prior migration, and it indeed recreated the database, with a table for the new entity as well.)
If you have additional questions, feel free to comment, and I'll address them. :)

EF6 Foreign Key Conflict

This is the content of my DivorceCases.cs file inside Models:
public class DivorceCases
{
public string case_id { get; set; }
public virtual Transactions t { get; set; }
}
public class DivorceCasesContext : DbContext
{
public DivorceCasesContext() : base("mssqlDB") { }
public DbSet<DivorceCases> DivorceCase { get; set; }
}
This is the content of my CorporationCases.cs file inside Models:
public class CorporationCases
{
public string case_id { get; set; }
public virtual Transactions t { get; set; }
}
public class CorporationCasesContext : DbContext
{
public CorporationCasesContext() : base("mssqlDB") { }
public DbSet<CorporationCases> CorporationCase { get; set; }
}
Now my question is:
I am using code-first approach to let EF6 create table for me automatically.
when I try to create and use any instance of table and EF6 creates it as well for DivorceCases Model and Context pair. But after the DivorceCases table has been created, I try to create and use CorporationCases Model instance then EF6 fails to automatically create the table for me because
"Transaction" Table has already been created by DivorceCases context
So how do I solve this issue?
You don't need to create 2 dbContext here.just use one as shown below.
Important Note : You're not following basic naming conventions.I highly recommend to use those.
one place is here : public DbSet<DivorceCases> DivorceCase { get; set; }
need to be corrected as public DbSet<DivorceCase> DivorceCases { get; set; }
Using One DbContext :
public class DivorceCases
{
public string case_id { get; set; }
public virtual Transactions t { get; set; }
}
public class CorporationCases
{
public string case_id { get; set; }
public virtual Transactions t { get; set; }
}
public class YourCasesContext : DbContext
{
public YourCasesContext () : base("mssqlDB") { }
public DbSet<DivorceCases> DivorceCase { get; set; }
public DbSet<CorporationCases> CorporationCase { get; set; }
}

Entity Framework Code First Common Database Audit Fields

I'm new to Entity Framework, in the past I've used Enterprise Library or ADO.NET directly to map models to database tables. One pattern that I've used is to put my common audit fields that appear in every table in a Base Class and then inherit that Base Class for every object.
I take two steps to protect two of the fields (Created, CreatedBy):
Have a parameterless constructor private on the Base Enitity and create a second one that requires Created and CreatedBy are passed on creation.
Make the setters Private so that the values cannot be changed after the object is created.
Base Class:
using System;
namespace App.Model
{
[Serializable()]
public abstract class BaseEntity
{
public bool IsActive { get; private set; }
public DateTimeOffset Created { get; private set; }
public string CreatedBy { get; private set; }
public DateTimeOffset LastUpdated { get; protected set; }
public string LastUpdatedBy { get; protected set; }
private BaseEntity() { }
protected BaseEntity(DateTimeOffset created, string createdBy)
{
IsActive = true;
Created = created;
CreatedBy = createdBy;
LastUpdated = created;
LastUpdatedBy = createdBy;
}
}
}
Inherited Class:
using System;
namespace App.Model
{
[Serializable()]
public class Person : BaseEntity
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public Person(DateTimeOffset created, string createdBy) :
base(created, createdBy) { }
}
}
I've run into issues with both. EF requires a parameterless constructor to create objects. EF will not create the database columns that have a private setter.
My question is if there is a better approach to accomplish my goals with EF:
Require that the values for Created and CreatedBy are populated at instantiation.
The values of Created and CreatedBy cannot be changed.
You could instantiate a context with a constructor that accepts a string createdBy. Then in an override of SaveChanges():
public override int SaveChanges()
{
foreach( var entity in ChangeTracker.Entries()
.Where(e => e.State == EntityState.Added)
.Select (e => e.Entity)
.OfType<BaseEntity>())
{
entity.SetAuditValues(DateTimeOffset.Now, this.CreatedBy);
}
return base.SaveChanges();
}
With SetAuditValues() as
internal void SetAuditValues(DateTimeOffset created, string createdBy)
{
if (this.Created == DateTimeOffset.MinValue) this.Created = created;
if (string.IsNullOrEmpty(this.CreatedBy)) this.CreatedBy = createdBy;
}
After the entities have been materialized from the database the values won't be overwritten when someone calls SetAuditValues.
You shouldn't be trying to control access rights directly on your entities/data layer instead your should do this in your application layer. This way you have a finer level of control over what users can do what.
Also rather than have the audit fields repeated on every table you might want to store your Audit records in another table. This is easy to do with code first:
public class AuitRecord
{
public bool IsActive { get; set; }
public DateTimeOffset Created { get; set; }
public string CreatedBy { get; set; }
public DateTimeOffset LastUpdated { get; set; }
public string LastUpdatedBy { get; set; }
}
You would then link the base class with the audit record to it:
public abstract class BaseEntity
{
public AuditRecord Audit { get; set; }
}
And finally your actually entities
public class Person : BaseEntity
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
}
You can no access the audit data by going:
Person.Audit.IsActive

Entity Framework Creates unwanted relationship between abstract and derived tables

Using code first, I have some abstract classes and some classes derived from those abstracted classes.
// Abstracted Classes
public abstract class Brand
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
}
public abstract class Model
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
}
// Derived Classes
[Table("ComparisonBrand")]
public class ComparisonBrand : Brand
{
public ComparisonBrand()
{
ComparisonValues = new List<ComparisonValue>();
Models = new List<ComparisonModel>();
}
public virtual ICollection<ComparisonValue> ComparisonValues { get; set; }
public virtual ICollection<ComparisonModel> Models { get; set; }
}
[Table("ComparisonModel")]
public class ComparisonModel : Model
{
public int? BrandId { get; set; }
public int? LogoId { get; set; }
[ForeignKey("BrandId")]
public virtual ComparisonBrand ComparisonBrand { get; set; }
[ForeignKey("LogoId")]
public virtual ComparisonLogo ComparisonBrand { get; set; }
public virtual ICollection<ComparisonValue> ComparisonValues { get; set; }
}
My issue is that the migration generates foreign keys for:
ComparisonModel.Id > Models.Id
ComparisonModel.BrandId > Brands.Id
ComparisonModel.BrandId > ComparisonBrand.Id
Since ComparisonBrand.Id is a FK to Brands.BrandId, I get an error when deleting a Brand record. If I delete the ComparisonModel.BrandId > ComparisonBrand.Id relationship, however, the delete works fine.
How can I prevent a relationship from being formed between both the abstracted table and the derived table (Brands and ComparisonBrand)?
You are using the virtual keyword this causes Lazy Loading. You are telling EF to generate Foreign keys for them through this feature. Drop the virtual and you will not create the keys any longer

Categories

Resources