Inherited Relationship not working as expected - intersystems-cache

I have the following classes:
Class SearchTemplateDO [ Abstract ]
{
Relationship QueryParts As QueryPartDO [ Cardinality = many, Inverse = SearchTemplate ];
}
Class MyCustomSearchDO Extends (%Persistent, SearchTemplateDO)
{
/// inherits all properties / relationships from SearchTemplateDO
}
Class QueryPartDO Extends %Persistent
{
...
Relationship SearchTemplate As SearchTemplateDO
[ Cardinality = one, Inverse = QueryParts ];
Index SearchTemplateIndex On SearchTemplate;
}
When I look at these two tables in SQL I see that QueryPartDO's SearchTemplate field is empty and when I look at MyCustomSearchDO I do not see a "QueryParts" field, although both tables have data

from documentation
The MANY or CHILD side is not projected as a field, since these relationships are stateless on disk and SQL does not deal with in-memory objects. Instead, you must perform a simple join based on the ONE or CHILD side’s ID value and the MANY or PARENT side’s reference field:

You can't reference abstract parent in non-abstract child class, because abstract classes have no storage strategy defined. Both classes in relationship have to be either abstract (in this case there is no data stored at all) or non-abstract (in this case you'll have proper storage strategy)

In the end I was able to get this to work by extending %Persistent on the abstract class. Before when I tried it, nothing was working and I kept getting a strange error. However, I tried this in a sample project and now it works.

Related

What is the correct name of an relationship which is passed to Eloqent `Model::load()`?

I have to models Photo and SizeVariant. A photo has many size variants, a size variant has exactly one photo as its owner. The tables of the DB follow Eloquents naming scheme and are called photos and size_variants.
My models look like that (shortened down):
class Photo extends Model {
protected $with = [ 'size_variants' ];
public function sizeVariants(): HasMany {
return $this->hasMany(SizeVariant::class);
}
}
class SizeVariant extends Model {
protected $with = ['photo'];
protected $touches = ['photo'];
public function photo(): BelongsTo {
return $this->belongsTo(Photo::class);
}
}
However, when I try to call $photo->load('size_variants) on an existing $photo object, I receive an Illuminate\Database\Eloquent\RelationNotFoundException exception with message Call to undefined relationship [size_variants] on model [App\Models\Photo].
What is the right name of the relationship? I thought the naming scheme would follow Laravels usual pattern and Laravel magically maps between snake and camel case.
I already tried the all combinations of capitalizing, snake and camel case and plural vs. singular, i.e. $photo->load('size_variants'), $photo->load('size_variant'), $photo->load('sizeVariants'), $photo->load('sizeVariant'), $photo->load('SizeVariants') and $photo->load('SizeVariant').
Your relation name that is passed in with or load contexts should match the name of the relation you defined on your model, which in your case should be sizeVariants.
On another note, I would also be careful with always eager loading both relations by defining the protected $with property on both models. You'll end up getting timeouts because: your Photo model would be eager loading the SizeVariant models, which would eager load the Photo model, which would eager load the SizeVariant models, which would eager load the Photo model, etc.
You should remove the protected $with property and use with on your queries or load on your models whenever you need the related models instead to avoid this.

How to add a derived list to a model object

I'd like to add a derived list to a DTO/model object when mapping from an entity. For example, I have an entity class named Company that has a list of Employees. I'd like for the Company Model object to contain the list of Employees as well as a list of Employees who are Managers. (This is not my actual class names, but this type of thing is what I'm trying to do). So, I want the Company DTO to have a list of Employees and a list of Managers where the Managers is a subset of Employees that is derived by filtering the list of Employees.
I tried using a mapping expression and a default method. However, I need to use the EmployeeMapper and it seems that I don't have access to the mapper.
Here's what I tried...
#Mapper(componentModel = "spring", uses = {EmployeeMapper.class})
public interface CompanyMapper extends IEntityMapper<CompanyModel, Entity> {
#Mapping(expression = "java(deriveManagers(model))", target = "managers")
EntityModel toModel(Company company);
default List<EmployeeModel> deriveManagers(Company company) {
List<EmployeeModel> managers = new ArrayList<EmployeeModel>();
company.getEmployees().forEach(nextEmployee -> {
if (nextEmployee.getJobTitle().equals(JobTitle.MANAGER)) {
managers.add(this.EmployeeMapper.toModel(nextEmployee);
}
});
return managers;
}
}
I decided to do this processing in the DTO/Model object rather than in the Mapper. The list can be derived as a subset of the EmployeeModel objects in the CompanyModel object. Therefore, I think that this is the right place to derive this list. It is not really a mapping from Entity to Model object as much as it is a derived attribute in the Model object.

Need help understand interfaces and/or abstract classes in angular2

I am new to the angular2 world. I am trying to create interfaces for certain components and then implement these interfaces in my models so I can make sure they will be able to work properly.
One thing I have noticed is that if I create new instances of these objects they work fine but when I pull data from a restful call, I use the type casting to turn the data into the type of object I expect. The following code is a pseudo example.
I come from a Java/C++ background so I am hoping someone can see what I'm trying to do and explain to me how to get this working correctly.
Thanks In Advance!
Doesn't work ---
private vehicles: Vehicle[];
this._vehicleService.loadVehicles().subscribe(
vehicles => this.vehicles = <Vehicle[]>vehicles);
Does Work ---
vehicles : Vehicle[];
vehicles.push(new Vehicle(1, 'Old Junker'));
vehicles.push(new Vehicle(2, 'Old Junker2'));
Example class/interface setup.
#Component
export class SelectableComponent {
options : Selectable[]
// Access options.label and options.value
}
export interface Selectable {
label(): string;
value(): any;
}
export class Vehicle implements Selectable {
constructor (
public id: number,
public description: string,
){}
get label() : any {
return this.description;
}
get value() : any {
return this.id;
}
}
What happens here is that the object retrieved from the backend is just a plain Javascript object that gets cast to a Vehicle:
this._vehicleService.loadVehicles().subscribe(
vehicles => this.vehicles = <Vehicle[]>vehicles);
Objects in this array will have all the data of a Vehicle, but none of the behavior of an instance of the Vehicle class, which can be quite confusing as you mention.
The simplest is instead of casting them, calling new and creating an instance of Vehicle immediately while retrieving them from the backend.
But using a long constructor call can be cumbersome, especially if Vehicle has a lot of properties and you need to pass them all to the constructor one by one.
A way to fix this is to create an auxiliary method in the Vehicle class:
class Vehicle {
constructor(private name, private year) {
}
static fromJson({name,year}) {
return new Vehicle(name, year);
}
}
And then use it in return from the backend to create an array of Vehicles, instead of casting them:
this._vehicleService.loadVehicles().subscribe(
vehicles => this.vehicles = vehicles.map(Vehicle.fromJson));
This way the vehicles in the result will have not only all the data of a vehicle, but also the behavior of the Vehicle class, because they are instances on Vehicle.
The main difference between classes and interfaces in TypeScript is that interfaces don't exist at runtime. They are "only" there for compilation and type checking.
Casting an element to an interface / class "only" tells TypeScript that the object follows the structure of it but it's not actually an instance of the type. It's a bit disturbing at a first sight. The main consequence (in the case of a class) is that casting doesn't allow you to use methods of the class.
I already casted this way:
private vehicles: Vehicle[];
this._vehicleService.loadVehicles().subscribe(
vehicles => this.vehicles = <Vehicle[]>vehicles);
What is the exact compilation error you have?

Mixing Table-Per-Hierarchy and Table-Per-Type in Entity Framework Code First to Existing Database

tl;dr: I'm trying to map a code-first model to an existing database where a certain hierarchy of objects has a mixed inheritance scheme. Some concrete classes use TPH and some use TPT. I can't seem to get the mapping correct.
I have a hierarchy of objects which I'm trying to map to an existing database. Some of the concrete classes contain additional properties, so they have their own table; some of the concrete classes do not, so they live in the base table and rely on a discriminator column. To simplify things, I've created a POC. The database structure is like this:
CREATE TABLE Foos (
Id INT IDENTITY NOT NULL PRIMARY KEY,
FooType TINYINT NOT NULL
)
CREATE TABLE FooTpts (
Id INT NOT NULL PRIMARY KEY
FOREIGN KEY REFERENCES Foos(Id),
Value INT NOT NULL
)
And the equivalent POCOs would be:
public abstract class Foo
{
public int Id { get; set; }
}
public class FooTph : Foo {}
public class FooTpt : Foo
{
public int Value { get; set; }
}
Seems simple enough. So my first try was the following mapping (fluent or with attributes, the result is the same):
modelBuilder.Entity<Foo>()
.ToTable("Foos")
.Map<FooTph>(m => m.ToTable("Foos").Requires("FooType").HasValue(1))
.Map<FooTpt>(m => m.ToTable("FooTpts").Requires("FooType").HasValue(2));
But that didn't work because:
It wants to create the FooTpt.FooType descriminator in the FooTpts table
Trying to execute a command gives me the following error (presumably because of point #1 above):
(6,10) : error 3032: Problem in mapping fragments starting at lines 6, 11:EntityTypes ConsoleApplication1.FooTph, ConsoleApplication1.FooTpt are being mapped to the same rows in table Foo. Mapping conditions can be used to distinguish the rows that these types are mapped to.
Back to the drawing board. This answer suggests creating an intermediate abstract entity mapped to the parent (TPH) table. Everything can always be solved with another layer of abstraction, right? So I make a few changes:
+ public abstract class FooTptBase : Foo {}
- public class FooTpt : Foo
+ public class FooTpt : FooTptBase
And change the mapping:
modelBuilder.Entity<Foo>()
.ToTable("Foos")
.Map<FooTph>(m => m.ToTable("Foos").Requires("FooType").HasValue(1))
.Map<FooTptBase>(m => m.ToTable("Foos").Requires("FooType").HasValue(2));
modelBuilder.Entity<FooTpt>().ToTable("FooTpts");
The database now looks good and we have a single discriminator in the parent table. But something is still missing and we get the same error:
(6,10) : error 3032: Problem in mapping fragments starting at lines 6, 11:EntityTypes ConsoleApplication1.FooTph, ConsoleApplication1.FooTpt are being mapped to the same rows in table Foo. Mapping conditions can be used to distinguish the rows that these types are mapped to.
That doesn't really make sense because all FooTpts have to be a FooTptBase by definition, which should require FooType == 2. (It's almost as if the model builder is ignoring my intermediate FooTptBase abstract type?)
So, what am I missing? How can I accomplish what I'm trying to do?

Serializing List of base object types using XmlMessageFormatter

I have an object like so:
public class Intent
{
public List<Entity> Updates { get; set; }
}
Which I wish to serialize into XML for passing as a message using MSMQ. The list of type Entity can contain any number of instances of classes that inherit from Entity. For example, there may be:
public Person : Entity { /* ... */ }
public Vehicle : Entity { /* ... */ }
I'm using XmlMessageFormatter, which so far I have defined as:
XmlMessageFormatter _formatter =
new XmlMessageFormatter(new[] { typeof(T) });
Where T in this instance is Intent (as above).
Trouble is, when the code actually attempts to serialize the following exception occurs:
The type CoreApi.Domain.Person was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.
I believe this is because I need to tell the serializer somehow of the fact that Person is a child class of entity.
I've seen solutions that basically entail adorning Entity with multiple XmlInclude decorations, which in my scenario is unworkable as the list of inheritors of Entity is large and could grow - I don't want to constantly update this list as new inheritors are added.
I've seen other solutions that use XmlSerializer, passing in a list of known types, the trouble with this is that I somehow need to replace XmlMessageSerialiser with the XmlSerialiser instance which isn't compatible.