I have a number of inheritance hierarchies in my model. I'm using Entity Framework Core 3.1.2 with a Postgres database. Code First. I am trying to create a migration to generate my database tables.
I mapped my first abstract object
public DbSet<Asset> Assets { get; set; }
I learn that you can't map an abstract class without mapping a concrete descendant.
The corresponding CLR type for entity type 'Asset' is not instantiable and there is no derived entity type in the model that corresponds to a concrete CLR type.
So I map the descendants.
public DbSet<LinearAsset> LinearAssets { get; set; }
public DbSet<StructureAsset> Structures { get; set; }
public DbSet<BridgeAsset> Bridges { get; set; }
public DbSet<RoadAsset> Roads { get; set; }
and everything is good. Fantastic.
However. When I come to map my second inheritance hierarchy (and any other that I try) I get into this weird circular argument where I both must and must not map the children.
public DbSet<Attachment> Attachments { get; set; }
public DbSet<AssetAttachment> AssetAttachments { get; set; }
gives me
The entity type 'AssetAttachment' cannot be mapped to a table because it is derived from 'Attachment'. Only base entity types can be mapped to a table.
If I remove the mapping for AssetAttachments, I'm back to this
The corresponding CLR type for entity type 'Attachment' is not instantiable and there is no derived entity type in the model that corresponds to a concrete CLR type.
I've not been able to find any meaningful difference between the Asset inheritance hierarchy, which worked, and the other inheritance hierarchies, that don't work.
I've tried various different ways of mapping, or not mapping the descendant objects, but it always comes back to getting one of the two above error messages.
I am both expected to map and not map the descendants, leaving me very confused as to what Dot Net actually wants from me.
Is anybody able to give me some advice on how I am to deal with these two conflicting error messages?
It turns out, the problem was that I was converting the table names to snake case, to be consistence with postgres convention. Making the field names snake case was fine, but making the table names snake case introduced the error I describe above.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
foreach (var entity in modelBuilder.Model.GetEntityTypes())
{
// THIS IS WHAT CAUSES THE ISSUE
if (!String.IsNullOrWhiteSpace(entity.GetTableName()) && (entity.GetTableName() != entity.GetTableName().ToLower()))
entity.SetTableName(ToSnakeCase(entity.GetTableName()));
// THIS IS OKAY
foreach (var property in entity.GetProperties())
{
property.SetColumnName(ToSnakeCase(property.GetColumnName()));
}
}
base.OnModelCreating(modelBuilder);
}
With its recent improvements, I'm looking to move from Dapper back to EF (Core).
The majority of our code currently uses the standard patterns of mapping entities to tables, however we'd also like to be able to make simple ad-hoc queries that map to a simple POCO.
For example, say I have a SQL statement which returns a result set of strings. I created a class as follows...
public class SimpleStringDTO
{
public string Result { get; set; }
}
.. and called it as such.
public DbSet<SimpleStringDTO> SingleStringResults { get; set; }
public IQueryable<SimpleStringDTO> Names()
{
var sql = $"select name [result] from names";
var result = this.SingleStringResults.FromSql(sql);
return result;
}
My thoughts are that I could use the same DBSet and POCO for other simple queries to other tables.
When I execute it, EF throws an error "The entity type 'SimpleStringDTO' requires a primary key to be defined.".
Do I really need to define another field as a PK? There'll be cases where there isn't a PK defined. I just want something simple and flexible. Ideally, I'd rather not define a DBSet or POCO at all, just return the results straight to an IEnumerable<string>.
Can someone please point me towards best practises here?
While I wait for EF Core 2.1 I've ended up adding a fake key to my model
[Key]
public Guid Id { get; set; }
and then returning a fake Guid from SQL.
var sql = $"select newid(), name [result] from names";
Problem with: Dapper Extensions dbConnection.Get(personId)
I have a model called Person:
Person
{
public int PersonId { get; set; }
public string Name { get; set; }
}
In the database I have this table:
data.Persons
Pers_Id
Pers_Name
When I try this without any kind of custom mapping, I get an error "Invalid object name 'Person'."
I believe this is a mapping issue, because when I completely map the model with the prefix 'Pers_', and use 'data.Persons'
Get works.
But is there a way to automatically map with a prefix? The database I'm using has many different tables
with different prefices.
I also have everything already mapped to Entity framework. Is there a possibility of getting the map settings from
Entity DbModelBuilder?
Dapper-Extensions is convention based. For schema, it uses .dbo and for primary key it uses Id. If your tables don't match the convention, you will have to create a custom mapping.
public class MyModelMapper : ClassMapper<MyModel>
{
public MyModelMapper()
{
//use different table name
Table("table_name");
//use a custom schema
Schema("not_dbo_schema");
//have a custom primary key
Map(x => x.ThePrimaryKey).Key(KeyType.Assigned);
//Use a different name property from database column
Map(x=> x.Foo).Column("Bar");
//Ignore this property entirely
Map(x=> x.SecretDataMan).Ignore();
//optional, map all other columns
AutoMap();
}
}
An alternative is to use Dapper and just write your inline queries:
connection.Query("select * from foo.table where myId = {myId}", new {myId})
Update:
Another alternative is to play around with Code Generation and T4 Text Templates
Here is a trivial example
I have a simple hierarchy
public abstract class CommunicationSupport
{
public SupportTypeEnum Type { get; set; }
public Country Origin { get; set; } // National or Foreign support
}
public class TelecomSupport : CommunicationSupport
{
public string Number { get; set; }
}
public class PostalSupport : CommunicationSupport
{
public Address Address { get; set; }
}
I plan to use the Table-per-type hierarchy for my DB. So 3 tables will be created, one base and two child using the same PK as the base.
My problem is that I want to be able to update a CommunicationSupport by changing it's type.
Let's say that I create a TelecomSupport, save it and then change it's type to a PostalSupport and save it again (update). The result I expect is for EF to keep the same base record (CommunicationSupport Id) but delete the record in the TelecomSupport table and create a new one in the PostalSupport.
So TelecomSupport and PostalSupport are exclusive and cannot share the same base CommunicationSupport.
How can I do that using EntityFramework 5?
Thanks for your help!
I don't have a good answer, but I can think of four "solutions" that are really workarounds:
Don't use DBMS-computed values for your primary keys (if you already use natural keys, it's fine).
Use DBMS-computed surrogate keys.
Follow something like the state pattern.
Do some evil voodoo with the object state manager.
Update: There seems to be a popular consensus that trying isn't even worth it; most people thus simply use stored procedures instead to work around the problem.
Changing Inherited Types in Entity Framework
Entity Framework: Inheritance, change object type
Changing the type of an (Entity Framework) entity that is part of an inheritance hierarchy
Changing the type of an entity that is part of an inheritance hierarchy
Using natural keys
First, remember that the objects tracked by the EF are part of your DAL, not your domain model (regardless of whether you use POCOs or not). Some people don't need a domain model, but keep it in mind, as we can now think of these objects as representations of table records we manipulate in ways we wouldn't with domain objects.
Here, we use IDbSet.Remove to delete the records of the entity, then add new ones with the same primary key using IDbSet.Add, all in a single transaction. See the ChangeType method in the sample code below.
In theory, integrity is OK, and in theory, EF could detect what you're trying to do and optimize things. In practice, it currently doesn't (I profiled the SQL interface to verify this). The result is that it looks ugly (DELETE+INSERT instead of UPDATE), so if system beauty and performance are issues, it's probably a no-go. If you can take it, it's relatively straightforward.
Here is some sample code I used to test this (if you want to experiment, simply create a new console application, add a reference to the EntityFramework assembly, and paste the code).
A is the base class, X and Y are subclasses. We consider Id to be a natural key, so we can copy it in the subclasses copy constructors (here only implemented for Y). The code creates a database and seeds it with a record of type X. Then, it runs and changes its type to Y, obviously losing X-specific data in the process. The copy constructor is where you would transform data, or archive it if data loss is not part of the business process. The only piece of "interesting" code is the ChangeType method, the rest is boilerplate.
using System;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Linq;
namespace EntitySubTypeChange {
abstract class A {
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
public string Foo { get; set; }
public override string ToString() {
return string.Format("Type:\t{0}{3}Id:\t{1}{3}Foo:\t{2}{3}",
this.GetType(), Id, Foo, Environment.NewLine);
}
}
[Table("X")]
class X : A {
public string Bar { get; set; }
public override string ToString() {
return string.Format("{0}Bar:\t{1}{2}", base.ToString(), Bar, Environment.NewLine);
}
}
[Table("Y")]
class Y : A {
public Y() {}
public Y(A a) {
this.Id = a.Id;
this.Foo = a.Foo;
}
public string Baz { get; set; }
public override string ToString() {
return string.Format("{0}Baz:\t{1}{2}", base.ToString(), Baz, Environment.NewLine);
}
}
class Program {
static void Main(string[] args) {
Display();
ChangeType();
Display();
}
static void Display() {
using (var context = new Container())
Console.WriteLine(context.A.First());
Console.ReadKey();
}
static void ChangeType()
{
using (var context = new Container()) {
context.A.Add(new Y(context.A.Remove(context.X.First())));
context.SaveChanges();
}
}
class Container : DbContext {
public IDbSet<A> A { get; set; }
public IDbSet<X> X { get; set; }
public IDbSet<Y> Y { get; set; }
}
static Program() {
Database.SetInitializer<Container>(new ContainerInitializer());
}
class ContainerInitializer : DropCreateDatabaseAlways<Container> {
protected override void Seed(Container context) {
context.A.Add(new X { Foo = "Base Value", Bar = "SubType X Value" });
context.SaveChanges();
}
}
}
}
Output:
Type: EntitySubTypeChange.X
Id: 0
Foo: Base Value
Bar: SubType X Value
Type: EntitySubTypeChange.Y
Id: 0
Foo: Base Value
Baz:
Note: If you want an auto-generated natural key, you can't let EF ask the DBMS to compute it, or EF will prevent you from manipulating it the way you want (see below). In effect, EF treats all keys with computed values as surrogate keys, even though it still happily leaks them (the bad of both worlds).
Note: I annotate the subclasses with Table because you mentioned a TPT setup, but the problem is not actually related to TPT.
Using surrogate keys
If you consider a surrogate key to be truly internal, then it doesn't matter if it changes under your nose as long as you can still access your data the same way (using a secondary index for example).
Note: In practice, many people leak surrogate keys all around (domain model, service interface, ...). Don't do it.
If you take the previous sample, simply remove the DatabaseGenerated attribute and the assignment of the Id in the copy constructor of the subtypes.
Note: With its value generated by the DBMS, the Id property is completely ignored by EF and doesn't serve any real purpose other than being analyzed by the model builder to generate the Id column in the SQL schema. That and being leaked by bad programmers.
Output:
Type: EntitySubTypeChange.X
Id: 1
Foo: Base Value
Bar: SubType X Value
Type: EntitySubTypeChange.Y
Id: 2
Foo: Base Value
Baz:
Using the state pattern (or similar)
This solution is probably what most people would consider the "proper solution", since you can't change the intrinsic type of an object in most object-oriented languages. This is the case for CTS-compliant languages, which includes C#.
The problem is that this pattern is properly used in a domain model, not in a DAL like one implemented with EF. I'm not saying it's impossible, you may be able to hack things up with complex types or TPH constructs to avoid the creation of an intermediary table, but most likely you'll be swimming up the river until you give up. Hopefully someone can prove me wrong though.
Note: You can decide that you want your relational model to look different, in which case you may bypass this problem altogether. It wouldn't be an answer to your question though.
Using internal EF voodoo
I've rather quickly looked around the reference documentation for DbContext, ObjectContext and ObjectStateManager, and I can't immediately find any way to change the type of an entity. If you have better luck than me, you may be able to use DTOs and DbPropertyValues to do your conversion.
Important note
With the first two workarounds, you'll likely hit a bunch of problems with navigational properties and foreign keys (because of the DELETE+INSERT operation). This would be a separate question.
Conclusion
EF is not that flexible when you do anything non-trivial, but it keeps improving. Hopefully this answer won't be relevant in the future. It's also possible that I'm not aware of an existing killer-feature that would make what you want possible, so don't make any decisions based on this answer.
When creating POCO classes that contain collections of primitive types and are persisted by EF Code First, the best advice I have found so far is to create a new class that has an ID plus the primitive type:
Entity Framework and Models with Simple Arrays
If I now have several classes that require properties of type ObservableCollection<string> and replace them with ObservableCollection<EntityString> (where EntityString is a custom type with an Id and a string property), I end up with a table EntityString that has multiple foreign key columns, one for each property of type ObservableCollection<EntityString> across all concrete types with such properties.
This leads to a bloating of mostly-null foreign key columns in the EntityString table.
One approach would be to create a subclass of EntityString and use the Table per Type model for those subclasses. However, that requires making awkward changes to the object model simply to accommodate Entity Framework.
Questions:
Is the encapsulating type the best way to manage Collection<PrimitiveType>?
If so, what are the pro's and con's of allowing multiple (many) foreign key columns vs. creating custom tables per type (at the cost of an awkward model)?
Promoting simple type to entity is one option. If you want to use that new primitive type entity in more relations it is better to completely remove navigation properties from that entity and use independent association (no FK properties).
public class StringEntity
{
public int Id { get; set; }
public string Text { get; set; }
}
and mapping:
modelBuilder.Entity<Foo1>().HasMany(f => f.Strings).WithOptional();
modelBuilder.Entity<Foo2>().HasMany(f => f.Strings).WithOptional();
In database you will get new nullable FK per related principal - there is no way to avoid it except create special StringEntity class per principal (don't use inheritance for that because it affects performance).
There is an alternative:
public class StringEntity
{
public int Id { get; set; }
public List<string> Strings { get; private set; }
public string Text
{
get
{
return String.Join(";", Strings);
}
set
{
Strings = value.Split(";").ToList();
}
}
}
In this case you don't need related entity type (and additional table) but your entity is polluted with additional property Text which is only for persistence.