I'm having a trouble configuring May-to-many with TPC inheritance
public class TestB
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<ParentClass> ParentClasss { get; set; }
}
public abstract class ParentClass
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<TestB> TestBs { get; set; }
}
[Table("Child_A")]
public class Child_A: ParentClass
{
public string childAName { get; set; }
}
[Table("Child_B")]
public class Child_B: ParentClass
{
public string childbName { get; set; }
}
the many to many relation is on the abstract class, the generated tables are
TestB
ParentClass
ParentClassTestB : the many to many relation
Child_A : have FK for the ParentClass
Child_B : have FK for the ParentClass
what I need is to have the many to many directly with Child_A and Child_B.
so the generated tables will be something like
TestB
Child_A
Child_ATestB : the many to many relation table between Child_A and TestB
Child_B
Child_BTestB : the many to many relation table between Child_B and TestB
regards
what i need is to have the many to many directly with Child_A and Child_B.
Then don't map ParentClass as an Entity. You can still have it as the parent class in your code, but as far as the database is concerned Clild_A and Child_B are unrelated.
This is especially important in TPH, which has serious performance implications. This way there's simply no database overhead for your inheritance hierarchy. And the only real downside is that you don't have a built-in search over all ParentClass entities.
The only change is that if you don't want ParentClass involved in the M2M in the database, you can't have a navigation property from TestB to ParentClass. So
public class TestB
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Child_A> ParentClasssA { get; set; }
public ICollection<Child_B> ParentClasssB { get; set; }
}
public abstract class ParentClass
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<TestB> TestBs { get; set; }
}
[Table("Child_A")]
public class Child_A : ParentClass
{
public string childAName { get; set; }
}
[Table("Child_B")]
public class Child_B : ParentClass
{
public string childbName { get; set; }
}
Related
Here is an example of declaring a single parameter generics class with single constraints.
public class TestClass<T> : ITestClass<T> where T : Teacher
I am looking for a way to declare the TestClass with multiple constraints. Where I will be able to use an interface for different classes.
How can I do something like this?...
public class TestClass<T> : ITestClass<T> where T : Teacher, Student, new()
My classes look like
public class Teacher{
public string Name { get; set; }
public string Designation { get; set; }
}
public class Student{
public string Name { get; set; }
public int Roll { get; set; }
public string Department { get; set; }
}
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?
I have 2 models which have exactly same fields, but I chose to make different models for them because I needed two different tables, one for each.
Earlier everything was working fine when I had two different tables for each model, but then I started using abstract base class because the code inside both the models were same.
Now I have a single table comprised of all the data that I save.
How can I create different tables for those two models.
public abstract class baseGrammar
{
[Key]
public int Id { get; set; }
[Required]
public string question { get; set; }
[Required]
public string ans { get; set; }
public string ruleId { get; set; }
public string ruleApplicable { get; set; }
[ForeignKey("ruleId")]
public virtual ruleTable RuleTable { get; set; }
}
The one shown above is my abstract base class.
public class article : baseGrammar
{
}
public class adjective : baseGrammar
{
}
Just if someone intrested in ruleTable model.
public class ruleTable
{
[Key]
public string ruleId { get; set; }
public string topic { get; set; }
public string rule { get; set; }
public string example { get; set; }
public virtual ICollection<baseGrammar> BaseGrammar { get; set; }
}
Am also adding context class so as to provide better description
public class english : DbContext
{
public english() : base("name=localServerEng")
{
Database.SetInitializer<DbContext>(null);
Database.SetInitializer<english>(new UniDBInitializer<english>());
}
public virtual DbSet<adjective> adjectiveDb { get; set; }
public virtual DbSet<adverb> adverbDb { get; set; }
public virtual DbSet<alternativeVerb> alternativeVerbDb { get; set; }
public virtual DbSet<antonyms> antonymsDb { get; set; }
public virtual DbSet<article> articleDb { get; set; }
private class UniDBInitializer<T> : DropCreateDatabaseIfModelChanges<english>
{
}
public System.Data.Entity.DbSet<StructureSSC.Areas.AreaEnglish.Models.baseGrammar> baseGrammars { get; set; }
}
Screenshot of SQL Server showing 1 table comprising of all columns instead of different tables
This set up will give you 2 tables: (1) adjectives (2) articles
The context should be like this:
public class SomeContext : DbContext
{
public SomeContext()
: base("name=SomeContext")
{
}
public virtual DbSet<article> Articles { get; set; }
public virtual DbSet<adjective> Adjectives { get; set; }
}
public abstract class baseGrammar
{
//... common properties/columns
}
public class article : baseGrammar
{
}
public class adjective : baseGrammar
{
}
Please note the naming convention. In .NET class names and property names should follow Pascal Notation. Therefore, they should be:
BaseGrammar
Article
Adjective
RuleApplicable // other properties should follow same convention
I have the following requirement, on my app the Entities will come with some fields, however the user needs to be able to add additional fields to the entity and then values for those fields.
I was thinking something like this but I am not sure if it would be a good approach or not.
The base class is an entity (Not sure which fields I need to add here)
public class Entidad
{
}
Then the Company Class will inherit from Entity
public class Empresa : Entidad
{
[Key]
public int Id { get; set; }
public string Nombre { get; set; }
public string NIT { get; set; }
public string NombreRepresentanteLegal { get; set; }
public string TelefonoRepresentanteLegal { get; set; }
public string NombreContacto { get; set; }
public string TelefonoContacto { get; set; }
public ICollection<CampoAdicional> CamposAdicionales { get; set; }
}
As you can see there is an ICollection of additional fields. that class would have the fieldname, type and id
public class CampoAdicional
{
[Key]
public int Id { get; set; }
public string NombreCampo { get; set; }
public Tiposcampo TipoCampo { get; set; }
}
and then the field value would be something like this:
public class ValorCampo
{
public Entidad Entidad { get; set; }
public CampoAdicional Campo { get; set; }
public string ValorTexto { get;set ; }
public int ValorNumerico { get; set; }
}
However I am not sure if this is the correct model classes for my scenario and whether it would create the tables correctly.
EF works with lazy load so at least there are several "virtual" missings.
In all properties that does not use primitive types and in collections.
Can you extend more than one entity with additional fields? If so you need that ValorCampo contains the entity (Entidad) but the entity should have the Id so you need to move the Id from Empresa to Entidad. Otherwise you need ValorCampo should refer to Empresa not to Entidad
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