EF Core: ignore base class on table inheritance - entity-framework-core

I'm trying to use the Fluent API to use the TPH for mapping an existing class hierarchy into a single table. In this case, I've got a base class (holds common properties) and then 2 concrete classes that extend the base class with its own properties:
class Base
{
// properties
}
class A: Base {}
class B: Base {}
I'm trying to map the classes to the tables by using a custom type configurator and I thought that I could do it like this:
class BaseConfigurator: IEntityTypeConfiguration<Base>
{
public void Configure(EntityTypeBuilder<Base> builder)
{
builder.ToTable("...");
// more mappings
builder.HasDescriminator(e => e.Type)
.HasValue<A>("A")
.HasValue<B>("B");
}
}
When I try to run the code, I get an error message which says that the base type is part of the hierarchy, but does not have a discriminator value configured.
Since the base type is abstract and it's there only to be save the common properties, how can I say that the base type should be ignored?
Thanks.

Just noticed that I'm missing the abstract qualifier from the base class declaration...adding it seems to solve the problem.

Related

Why we cannot mark the visibility of a class as "protected" in kotlin?

I am new to kotlin I have been learning about inheritance in kotlin recently, and then I realised that we cannot mark the visibility of a class as "protected". Correct me if i am wrong, or is there any other way to make a class protected ?
You can mark protected only parts of classes, so that they become accessible only from the derived classes. You can mark protected a member property, a member function or a nested class:
open class X {
protected val v: SomeType = someValue
protected fun f() { }
protected class Y { ... }
}
But you cannot mark protected anything that does not belong to a class (e.g. a top-level class or function), because the modifier would make no sense: a top-level entity is not subject to inheritance, thus there can be no derived class that would access it.

Guice Assisted Inject with Providers or FactoryModuleBuilder

This is kind of a weird use-case and I need some help in figuring out how to use Assisted/Providers/FactoryModuleBuilders in conjunction with each other. Ignore the absence of #Singleton. This is just an example.
A set of traits belonging to a library I cannot change have the following pattern. It uses Cake Pattern.
trait A { //Has abstract methods and abstract service 'webService' }
trait B extends A { //First Concrete Service Implementation assigned to 'webService' }
trait C extends A { //Second Concrete service Implementation assigned to 'webService' }
Since the traits cannot be directly injected, I created a wrapper that would allow them to be injected
BB extends B
CC extends C
In my code, I have a Controller that depends on a Service, that in turn depends on the library. The service should be able to either use "BB" or "CC" depending on what the controller needs. So the components look like the following
I create my service as
//Note: Uses 'trait A' with #Assisted
class SomeWebServiceComponent #Inject()(#Assisted aInstance: A, foo: Foo){
//Do something with aInstance
}
The Factory to create this (should be created by Guice by using FactoryModuleBuilder)
class SomeServiceFactory {
def getWebServiceComponent(a:A) SomeWebServiceComponent
}
The FactoryModule will look something like this
class ApplicationModule extends AbstractModule {
override def configure() = {
install(new FactoryModuleBuilder().build(classOf[SomeServiceFactory]))
}
}
I don't mind annotating the controllers with the actual classes that I need.
class OneController #Inject()(factory: SomeServiceFactory, bb: BB) extends Controller {
val webServiceComponent = factory.getWebServiceComponent(bb)
}
class AnotherController #Inject()(factory: SomeServiceFactory, cc: CC) extends Controller {
val webServiceComponent = factory.getWebServiceComponent(cc)
}
With this setup, I get errors of the following kind
No implementation for 'A' annotated with #com.google.inject.assistedinject.Assisted(value=) was bound
I need to understand how I can tell Guice that there are two implementations for Trait A, namely, BB and CC and the choice will be supplied at runtime.
Is there a way to achieve this use-case?
Ok, I created a separate project to test this whole scenario.
And it works the way the question is framed.
It turns out, the test cases that I were using, were not currently using GuiceInjection directly. The error message was however, so specifically related to GuiceInjection that I never investigated if the test setup was correct.
Changing the test base, resolved the issue.

Scala: force type parameter to be a case class

I have an abstract class Model from which I create case classes:
abstract class Model
case class User(.) extends Model
an abstract class Table taking such a Model as type parameter, used in one of its default concrete methods:
abstract class Table[M <: Model] {
def parser = SomeExternalBuilder[M]
}
The meaning is rather simple: "Give every instance of Table a default parser based on its own class".
The problem is that SomeExternalBuilder will only accept a case class as argument ("case class expected: M"), so it does not compile.
Can I make Table take only case classes as type parameter?
I have seen a few answers providing a missing copy method (ref1, ref2), so I tried this:
trait Model[T] {
def copy: T
}
abstract class Table[M <: Model[M]]
but now case class User extends Model[User] and must overwrite copy too, every function creating a Model takes a type parameter, and honestly the code quickly starts being atrocious, all that for that single line in Table.
Is there no better way than copying that def parser line in every child's body?
Edit: N.B. The real function is def parser: anorm.Macro.namedParser[M] from the "anorm" library for Play.
Edit: Source of the type check by this macro: https://github.com/playframework/anorm/blob/0a1b19055ba3e3749044ad8a54a6b2326235f7c8/core/src/main/scala/anorm/Macro.scala#L117
The problem is that SomeExternalBuilder will only accept a case class as argument ("case class expected: M"), so it does not compile.
I don't think you can ever get such a message from Scala compiler itself, which means that SomeExternalBuilder.apply is a macro. It requires a specific case class in order to know its fields, so that it doesn't matter if you could limit M to be a case class (which you can't): it still wouldn't accept a type parameter.
What you can do is create a macro annotation, so that when you write e.g.
#HasModel
class SomeTable extends Table[SomeModel] {
...
}
the val parser = namedParser[SomeModel] is generated automatically.
Alternately, write #HasModel[SomeModel] class SomeTable { ... } and generate extends Table[SomeModel] as well.
It wouldn't be hard (as macros go), but you still need to annotate each class extending Table.
Not fool proof solution but worth a try
case classes extend Product and Serialisable. Constraint Product with Serialisable will help you get some type safety. M can be any class which extends Product with Serialisable. But Product is extended by case class mostly
abstract class Table[M <: (Product with Serializable)] {
def parser = SomeExternalBuilder[M]
}

autofac Register closed subclasses of abstract open generic

public class Sub1 : Base<SomeClass>
{
// for sake of getting injection to work, not injecting anything in ctor
public Sub1() {}
....
}
public class Sub2 : Base<SomeOtherClass>
{
// for sake of getting injection to work, not injecting anything in ctor
public Sub2() {}
....
}
public abstract class Base<T>
{
// abstract, so no ctor
....
}
I tried the following but I'm getting the exception listed below. Notice it the exception references the Base abstract class. What am I missing?
builder.RegisterAssemblyTypes(typeof(Base<>).Assembly)
.Where(t => t.IsSubclassOf(typeof(Base<>))).AsClosedTypesOf(typeof(Base<>)).InstancePerDependency();
No constructors on type 'Base`1[SomeClass]' can be found with the constructor finder 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder'.
I think you mixed with generic and non generic abstract class registrations.
You have generic abstract class. Therefore your register should be like this:
builder.RegisterAssemblyTypes(typeof(Base<>).Assembly).AsClosedTypesOf(typeof(Base<>)).InstancePerDependency();

GORM inhertiance and fetching the super class

I have the following grails domain objects
abstract class A {
String name
}
class B extends A {
String propertySpecificToB
}
class C extends A {
String propertySpecificToC
}
and I can successfully save them to my database (which in this case is MongoDB). However, I would like to list all the names of the rows in my database, so I do something like:
A.list()
But, that throws an InstantiationException as it tries to create instances of the abstract class A. How can I list off all rows (regardless of which class it is). I could make A non-abstract, but it would never be valid to have a A. Also, I'd like to place some abstract methods in A.
I'd really just like it to return a list of A, with the list actually containing Bs and Cs.
I found a related post, but that didn't solve this problem.