EF6 Mapping base class properties and derived with different tables - c#

I'm using Entity Framework 6 and I have the following base class
public class ModelBase
{
public int ModelBaseId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public IList<Notification> Notifications { get; set; }
public IList<Assignable> Viewers { get; set; }
}
and a derived
public class Model : ModelBase
{
public int ModelId { get; set; }
public User Owner { get; set; }
public DateTime Date { get; set; }
public string Observations { get; set; }
public User Assignament { get; set; }
}
The ModelBase properties are populated with the same data for all derived class instances. I want to map the base entity properties with a table(A) and properties of the derived class with another table(B). And when I add Model just insert in the table B.
Is there any way to do this?? Is something complex to explain but I've tried to simplify my problem.
Thanks in advance!

Assuming you are using Codefirst...
You should try mapping them..
public class ModelBaseMap:EntityTypeConfiguration<ModelBase>
{
public ModelBaseMap()
{
this.toTable("ModelBase");
}
}
public class ModelMap:EntityTypeConfiguration<Model>
{
public ModelBaseMap()
{
this.toTable("Model");
}
}
I think it should work

Related

c# MVC Entity framework model property of type list containing multiple types

I am currently working on a C# MVC project combined with Entity Framework, where I have a view page (Create page) on which the users will need to fill in the required data. I got a model something like the code below. Where the user has a Boat and can select its properties.
public class Boat {
public string Name{ get; set; }
}
public class Slowboat : Boat {
public int Length { get; set; }
public virtual Engine SpeedSource { get; set; }
}
public class Speedboat : Boat {
public virtual List<?> SpeedSource { get; set; }
public int Topspeed {get; set; }
}
public class Engine {
public string EningeType { get; set; }
public int Horsepower { get; set; }
public string Manufacturer { get; set; }
}
public class Sail {
public int SailCount { get; set; }
public List<int> SailSizes { get; set; }
public string Manufacturer { get; set; }
}
Everything goes well, a Speedboat has a couple of sails or an engine.
The problem arises when a Speedboat has one or more Engine(s) and Sail.
I tried using List<object> type, but this didn't store my data into my database on posting. A kind of wrapper class like underneath is quick solution but there needs to be a better one in my opinion.
public class SpeedPower {
public Engine Engine_ { get; set; }
public Sail Sail_ { get; set; }
}
So my question is: how do you store multiple types into one list?
Thanks for a possible solution.
Edit: so as Thomas Flinkow suggested I can make an interface with some of the mutual properties.
public interface ISpeedSource {
string Manufacturer { get; set; }
}
public class Speedboat : Boat {
public virtual List<ISpeedSource> SpeedSource { get; set; }
public int Topspeed {get; set; }
}
So will the other proprties be saved if I use the interface like this?
You can define all your "speed sources" like this:
public class Engine : ISpeedSource { ... }
public class Sail : ISpeedSource { ... }
with ISpeedSource being a simple (maybe empty, but not necessarily) interface
public interface ISpeedSource { ... }
And then have your Speedboat class like this:
public class Speedboat : Boat
{
public virtual List<ISpeedSource> SpeedSource { get; set; }
public int Topspeed { get; set; }
}
You might want to overthink your design as David suggested, because empty interfaces should be avoided.

Entity Framework Code First - Abstract model class without primary key

I have model with defined primary key, but now I need to add inheritance to this class from my abstract class. The problem is, that primary key is required also to abstract class. Names of the PK's properties are different and they have to be different.
Example:
public abstract class AbstractModelClass
{
public int AbstractModelClassId { get; set; } // this key is required but I want him to not to be because I don't want to have 2 PK's
public string Prop1 { get; set; }
}
public class ModelClass : AbstractModelClass // before this class was not inherited but now I need this
{
public int ModelClassId { get; set; }
public int Prop2 { get; set; }
}
Why can't the primary key be in the abstract class but in database it is different tables? Check out Table per Concrete Type (TPC) approach in EF. Good explanation here:
https://weblogs.asp.net/manavi/inheritance-mapping-strategies-with-entity-framework-code-first-ctp5-part-3-table-per-concrete-type-tpc-and-choosing-strategy-guidelines
Sample:
public abstract class BillingDetail
{
[DatabaseGenerated(DatabaseGenerationOption.None)]
public int BillingDetailId { get; set; }
public string Owner { get; set; }
public string Number { get; set; }
}
public class BankAccount : BillingDetail
{
public string BankName { get; set; }
public string Swift { get; set; }
}
public class CreditCard : BillingDetail
{
public int CardType { get; set; }
public string ExpiryMonth { get; set; }
public string ExpiryYear { get; set; }
}
public class InheritanceMappingContext : DbContext
{
public DbSet<BillingDetail> BillingDetails { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<BankAccount>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("BankAccounts");
});
modelBuilder.Entity<CreditCard>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("CreditCards");
});
}
}
In this case I don't see the purpose of AbstractModelClassId in AbstractModelClass so one solution would be not having it.
However is for some reason you need that property, but don't want that it gets into Db table then you could add [NotMapped] attribute to it.
[NotMapped]
public int AbstractModelClassId { get; set; }

Trying to create different tables for different models which are using same base abstract class

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; }
}
Image of SQL Server showing 1 table comprising of all columns instead of different tables
Add table data annotation:
[Table("TABLE_NAME")]
Your class will look like:
[Table("articles")]
public class article : baseGrammar
{
}
you can use Table-Per-Concrete Class (TPC) Pattern using This Configurations
on OnModelCreating fuction
modelBuilder.Entity<baseGrammar>()
.Property(c => c.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
modelBuilder.Entity<article>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("article");
});
modelBuilder.Entity<adjective>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("adjective");
});

Table per hierarchy not default behavior of EF6

I'm trying to map these three classes to one EF table. In this scenario, my base class actually has a base Entity class, is this causing my issue? I'm not finding any examples that cover a scenario where the default behavior isn't handled properly.
Base Class:
public abstract class Connection : Entity
{
public override int Id { get; set; }
public ContactEnums.ConnectionType Type { get; set; }
public string Value { get; set; }
}
Child Classes:
public class BusinessConnection : Connection
{
[ForeignKey("Business")]
public int BusinessId { get; set; }
public Business Business { get; set; }
}
public class ContactConnection : Connection
{
[ForeignKey("Contact")]
public int ContactId { get; set; }
public Contact Contact { get; set; }
}
Entity Base class:
public abstract class Entity : EqualityAndHashCodeProvider<Entity, int>
{
public override int Id { get; set; }
public string CreatedBy { get; set; }
public DateTime CreatedDate { get; set; }
public string UpdatedBy { get; set; }
public DateTime UpdatedDate { get; set; }
[NotMapped]
public ObjectState ObjectState { get; set; }
}

Navigate properties when using Dapper Extensions

Im using DapperExtensions library for simple CRUD operations.
When I add a navigate property to my model, I get an error message that this column is not in the database. Can you in any way change this so that Dapper Extensions ignores this property?
Example of my model
public class Order : EntityBase
{
public int OrderId { get; set; }
public int MarketId { get; set; }
public int ModelId { get; set; }
public int ContactId { get; set; }
public string Project { get; set; }
public decimal Undertaking { get; set; }
public virtual Model Model { get; set; }
public virtual Contact Contact { get; set; }
}
Use the Write attribute above the property
[Write(false)]
add the package for dapperextentions
AutoMap(); will map all other properties as long as you have the same name for the field.
public class CustomMapper : DapperExtensions.Mapper.ClassMapper<Photo>
{
public CustomMapper()
{
Table("TableName if diffrent than the Model calss name");
Map(f => f.SomePropertyIDontCareAbout).Ignore();
AutoMap();
}
}

Categories