Entity Framework - Multiple classes (tables) of the same interface - DbSet exposure? - c#

public interface IQuestion {
// A couple of common properties go here, like Name, etc
}
/* Now follows multiple implementations of my interface, each of which has some custom properties */
public class TextBoxQuestion: IQuestion {
public int MaxLength { get; set; }
}
public class DateQuestion: IQuestion {
public DateTime MaxDate { get; set; }
public DateTime MinDate { get; set; }
}
public class MyRepo : DbContext {
**public DbSet<IQuestion> { get; set; } // Problem**
}
How would I go about implementing my DbContext? I can't expose an interface, as EF requires concrete implementations, which of course make sense, given the fact that I also have to generate a database.
Should I be exposing every IQuestion implementation I have, in the DbContext?
What is a better design - one huge table with all possible properties + discriminator column, or separate table for each implementation?
Edit:
I have added
public class BaseQuestion : IQuestion {
// Implements the common properties, plus:
[Key]
public int Id { get; set; }
}
and changed the Context to:
public class MyRepo : DbContext {
public DbSet<BaseQuestion> { get; set; }
}
EF now generates a 'huge table' + Discriminator column for me. The table 'automatically' includes the properties of all classes in my solution, which inherit the BaseQuestion. Is this the best practice?

Related

How to handle class inheritance in LiteDB with custom IDs

I would like to persist a class which implements an interface and can have various subclasses. I am just trying to understand how LiteDB handles this setup.
In particular I have a code structure like so:
public interface IItem
{
string UniqueKey { get; set;
string OtherProperties { get; set; }
}
public class Item : IItem
{
public string UniqueKey { get; set; }
public string OtherProperties { get; set; }
}
public class ItemOne : Item
{
public string ItemOneProperty { get; set; }
}
public class ItemTwo : Item
{
public string ItemTwoProperty { get; set; }
}
public class Main
{
public void Init()
{
// Can this apply to all interface implementations?
BsonMapper.Global.Entity<IItem>().Id(oid => oid.UniqueKey);
// This will apply to Item but not ItemOne or ItemTwo
BsonMapper.Global.Entity<Item>().Id(oid => oid.UniqueKey);
}
}
For reasons of wanting to keep the class structure clean, I do not want to use [BsonId] on the key. This means I need to use the BsonMapper to declare the ID. However, it looks like even though the mapper defines the ID on the base interface, it does not apply to any of the concrete classes.
Ideally, I do not want to declare the ID for every subclass in BsonMapper as - aside from there being many subclasses - it would create an unwanted dependency.
Does anyone know the best approach to solve this issue?

Mapping all derived types of a generic type in one table

I have a question concerning EF Core 2.1
I have a base type, let's name it Customer, from which CustomerOld and CustomerNew are derived. These are automatically stored in one table, so far so good.
Now I have a generic type for mapping Customer to Product :
public class CustomerToProduct<T> where T : Customer
{
public int CustomerId { get; set; }
public T Customer { get; set; }
public int ProductId { get; set; }
public Product Product { get; set; }
...
}
The derived types of CustomerToProduct have no specific properties. I just want to use them such as the Customer I access through the property CustomerToProduct.Customer is of the derived type.
I defined the DbSets for the derived types in my DbContext as follows, which of course leads to separate tables:
public class MyDbContext : DbContext
{
public DbSet<OldCustomerToProduct> OldCustomerToProducts { get; set; }
public DbSet<NewCustomerToProduct> NewCustomerToProducts { get; set; }
...
}
How do I store all derived Types of CustomerToProduct<T> in the same table? How do I define the DbSets<>?
Yours looks like a good candedate for the mapping pattern TPH (Type per Hierarchy).
You can read more here about the topic.

Data annotations on models when there are multiple repository implementations

My DTOs are pretty simple classes.
public class PlainClass {
public int Id { get; set; }
public string Name { get; set; }
public List<PlainSubClass> SubObjects { get; set; }
}
public class PlainSubClass {
public int Id { get; set; }
public string Name { get; set; }
}
I have a repository interface, whose implementations are meant to retrieve data.
public interface IRepository
{
IEnumerable<PlainClass> PlainObjects { get; }
}
Now, I want to implement that interface in another class mocking the database and also using EF SQLite, and possibly more in the future. My mock is simple but, in trying to implement and then generate the database I'm getting an error back stating I need to designate a primary key.
Now, how should I go about doing that? Should I build out interfaces for my models and add annotations specific to each implementation? Should I -- if it's even possible -- add multiple sets of annotations to the models?

Stop EF Inheritance

I have threeType MaliOp, LoanEBD, PrmEBD
public class MaliOp
{
public int Id { get; set; }
public int OldId { get; set; }
public byte MaliTable { get; set; }
public string Date { get; set; }
public short OpState { get; set; }
}
public class LoanEBD : MaliOp
{
public int? BId { get; set; }
public int? Loan { get; set; }
public int? PayerBimeGozar { get; set; }
[NotMapped]
public int OldId { get; set; }
}
public class PrmEBD : MaliOp
{
public int? PayerBimeGozar { get; set; }
public int? BId { get; set; }
[NotMapped]
public int OldId { get; set; }
}
the two Entity PrmEBD and LoanEBD Inherit from MaliOp. I want create DBContext in Entity Framework by by using this three types.
I have three Table in Database fro each one of them.
I don't want to use any EF Inhertance Strategy and add each one as Independent Types. but can't and EF Use either one of Inhertance strategy.
How can I do that?
create a IMaliOp Interface and let MaliOp implement it.
let the two classes implement the IMaliOp interface as well
Then use automapper (or something similar) to automatically transfer the information from the Entity object to your regular object.
This two classes would represent DTO (data transfer object). there are many strategies, out there for DTO-s
You should avoid having Classes inherit Entities, otherwise you applications classes will get too tightly coupled, and changes might prove them self to become too painful
In your context, override OnModelCreating;
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<PrmEBD>().ToTable("PrmEBDs");
modelBuilder.Entity<LoanEBD>().ToTable("LoanEBD");
modelBuilder.Entity<MaliOp>().ToTable("MaliOp");
}
This will create three separate tables in your database.
You will need to make sure that when you do a query over MaliOp, that you don't pull in instances from all three tables. You may want to go wit the approach of creating a common interface for all three, so that they don't actually inherit from each other, too

How to store two same entities in a database? Entity framework, c#

I have two entities with exactly the same properties:
public class Oil
{
public Guid Id { get; set; }
public string Title { get; set; }
public int Price { get; set; }
public int Ammount { get; set; }
}
public class Filter
{
public Guid Id { get; set; }
public string Title { get; set; }
public int Price { get; set; }
public int Ammount { get; set; }
}
Questions:
1) Can I somehow store them in one table? If so, than how?
2) Or should I implement inheritance? And what type then?
Edits:
In my case these two entities are just the same, they will not have any different properties in the future.
I implemented Table-per-Hierarchy approach, but there is another issue
(I have another type that has collections of oils and filters):
public class Warehouse
{
public Guid Id { get; set; }
public ICollection<Filter> Filters { get; set; }
public ICollection<Oil> Oils { get; set; }
}
So, when I create database, I get Warehouse_Id and Warehouse_Id1 fields in it. I don't want the Oil and Filter classes to have Warehouse property in them, how can I get just one field for Warehouse id in the db table?
If I include WarehouseId as a property in OilFilterBase class I will get 3 warehouse_id in the database table.
p.s. I also have DbSet<Oil> and DbSet<Filter> in my Context and don't have DbSet<OilFilterBase>.
It's hard to say what's best without knowing more about your requirements. What makes these two entities different? If they perform different functions and just happen to have the same properties, then it would probably be a good idea to store them in separate tables; that makes the most sense conceptually, and it would make things much easier if, say, you decided you wanted to add additional properties to one of them in the future.
On the other hand, if they're really the same at every level, it's also worth asking if you really need two different entity types to store them.
For the middle ground where the two classes serve related purposes but also differ in some ways, then yes, some form of inheritance might be a good approach -- either having one entity type derive from the other, or creating a new common base type and having both entities derive from that.
If you decide this is the best approach, then it looks like a good candidate for Table-per-Hierarchy mapping. You could restructure your code something like this:
public abstract class OilFilterBase
{
public Guid Id { get; set; }
public string Title { get; set; }
public int Price { get; set; }
public int Amount { get; set; }
}
public class Oil : OilFilterBase
{
}
public class Filter : OilFilterBase
{
}
...and then the Entity Framework will, by default, create a single table with an automatically-generated discriminator column, and store all instances of both entity types in that table.
If you decide that either of those entity types should have additional fields, then you could look at some of the other inheritance options, like Table-per-Type, that create separate but related tables for each entity type.
The first thing to do is decide how these classes fit together conceptually, and then figure out the best way to implement that in EF terms. If you can give more information about what these entities are and how they work, it'll be easier for people here to give good advice.
Response to Edits:
I think what's happening with the extra columns (Warehouse_Id and Warehouse_Id1) is this:
Because you're setting up the relationships for Oil and Filter separately, it's not comfortable assuming you want to use the base class's WarehouseId property as the foreign key -- what if you only wanted to set up that relationship for Oil and not Filter? It shouldn't be writing to the base class column in that case. So, it decides to create new properties instead.
Fortunately, you can use the [ForeignKey()] attribute (or the fluent API) to tell it what you really want, like this:
using System.ComponentModel.DataAnnotations.Schema;
public abstract class OilFilterBase
{
public Guid Id { get; set; }
public string Title { get; set; }
public int Price { get; set; }
public int Amount { get; set; }
public Guid WarehouseId { get; set; }
}
public class Oil : OilFilterBase
{
}
public class Filter : OilFilterBase
{
}
public class Warehouse
{
public Guid Id { get; set; }
[ForeignKey("WarehouseId")]
public virtual ICollection<Filter> Filters { get; set; }
[ForeignKey("WarehouseId")]
public virtual ICollection<Oil> Oils { get; set; }
}
Also, I think you'll need to include a DbSet<OilFilterBase> (in addition to DbSet<Oil> and DbSet<Filter>) in your context in order to get Table-per-Hierarchy inheritance to work -- try it and see.
Good luck!

Categories

Resources