One to many relation in pharo - pharo

how can we implement associations between classes in pharo. I tried this code to create a new classe. but, it doesn't work...
Object subclass: #SlotExampleMovie
slots: {
#name.
#year.
#director => ToOneRelationSlot opposite: #directedMovies class: #SlotExamplePerson.
#actors => ToManyRelationSlot opposite: #actedInMovies class: #SlotExamplePerson. }
classVariables: { }
category: 'SlotAssociations-Tests-Example'

I don't know where you got the selector opposite:class: from... The selector you're looking for is named inverse:inClass:. Your code would then look like this:
Object subclass: #SlotExampleMovie
slots: {
#name.
#year.
#director => ToOneRelationSlot inverse: #directedMovies inClass: #SlotExamplePerson.
#actors => ToManyRelationSlot inverse: #actedInMovies inClass: #SlotExamplePerson. }
classVariables: { }
category: 'SlotAssociations-Tests-Example'

I believe you do not need slots for that. You can just use instance variables.
Suppose you want to model the relationship between a book (an instance of class Book) and its authors (instances of class Person).
Then, you declare an "instance variable" called authors in class Book. That variable will hold a collection (a instance of some collection class), that in turn will hold the authors (instances of class Person)
Object subclass: #Book
instanceVariableNames: 'authors'
classVariableNames: ''
category: 'examples'
Then, you need to create (first of all) the collection. You do that in the initialize method of your Book class (this is the first message an object receives when it is created).
>> initialize
authors := Set new.
I used a set, but there are other collection objects.
Then you need a method in that class to tell a book when it has a new author:
>> addAuthor: someObject
authors add: someObject
Then, you can just use it, like this:
a := Book new.
p := Person new.
a addAuthor: p.
Because Pharo is dynamically typed (you do not need to explicitly type variables), the parameter to author: could be any object. With documentation and good variable names you can tell it should be a Person (in fact, the parameter should be better called aPerson).
Summary: The Book has a collection in its instance variable "authors". When you tell the book to add a new author (with the addAuthor: message ), it tells the collection to hold the object (with the add: message).

Related

DDD Entity and EntityType reference

I'm learning DDD and here is a problem I faced. I have two Aggregates (simplified):
class NoteType : AggregateRoot {
int noteTypeId
string name
string fields[]
... code omitted ...
}
class Note : AggregateRoot {
int noteId
int noteTypeId
map<str, str> fieldValues
setFieldValue(fieldName, fieldValue) {
// I want to check that fieldName is present in Notes.fields
// and later fieldValues[field.name] = fieldValue
}
... code omitted ...
}
I've heard that aggregates should reference to each other by ID's only. It this case I can't access NoteType.fields. I found several ways to do so, but not sure which one is better:
Pass NoteType instance into the Note model via constructor (do not reference by ID)
Use repository in setFieldValue to load NoteType
Use service which will do the check (this may cause all the Note logic to be implemented in this service, since Note highly dependent on NoteType)
What do you suggest?
What do you suggest?
Pass the information that the aggregate needs to the aggregate when it needs it.
setFieldValue(fieldName, fieldValue, noteType) {
// Now you have the data that you need to verify the noteType.fields
}
Sometimes, if you can't tell from outside the aggregate what information you need, then you instead pass the capability to look up that information
setFieldValue(fieldName, fieldValue, notes) {
// Use the provided capability to get what you need
noteType = notes.get(this.noteTypeId)
// the do the useful work
this.setFieldValue(fieldName, fieldValue, noteType)
}
Of course, if the only thing you need is the fields, then you might prefer to work only with that property:
setFieldValue(fieldName, fieldValue, fields)
Design is what we do, when we want to get more of what we want than we'd get by just doing it. -- Ruth Malan
In Domain Driven Design, a common "what we want" is to have the "business logic", meaning our implementation of the policies of information change that are important to our business, separated from the "plumbing" that describes how to read and store that information.

Node.js | Override Setter

I have a class instance (in my case the class is URL), called req_url. URL has a property that has a setter for one of its properties (search) that is implemented in a way that is problematic for me (doesn't just set the given value but does something to it first).
How can I override that setter without creating a class that inherits from URL (and then create a different setter)?
defineProperty doesn't work since it works at the Object level. I want to to do it on that specific type level.
Whenever you have an instance whose setter you want to bypass, calling Object.defineProperty on the instance to set the property does work:
class Foo {
set prop(arg) {
console.log('setter invoked');
}
}
const f = new Foo();
Object.defineProperty(f, 'prop', { value: 'val' });
console.log(f.prop);
It won't affect any object, it'll only affect objects you explicitly call Object.defineProperty with. The collisions with other objects you seem to be worried about won't occur.
Another (stranger) option would be to delete the setter on the prototype, though if the class is used elsewhere, outside of your code, it could cause problems:
class Foo {
set prop(arg) {
console.log('setter invoked');
}
}
delete Foo.prototype.prop;
const f = new Foo();
f.prop = 'val';
console.log(f.prop);

Cannot make a generic fake for a class using object

Cannot make a generic fake for a class using object like
Fakes.ShimDataServiceRepository<object>.AllInstances.GetEntitiesExpressionOfFuncOfT0Boolean = (instance, filter) =>
{
return null;
}
The call goes to actual code implementation.
But when we specify the object type, it is working
Fakes.ShimDataServiceRepository<Customer>.AllInstances.GetEntitiesExpressionOfFuncOfT0Boolean = (instance, filter) =>
{
return null;
}
But i need a general single fake for all objects so no need to repeat the code for each objects.
My question is why the fake with <object> is not working?. As it is the parent of all the classes.
Please any one help me :(
My question is why the fake with is not working?. As it is the parent of all the classes.
Object is the parent of all classes, but DataServiceRepository<object> is not the parent of DataServiceRepository<Customer>.
A generic class with different concrete types is no longer "the same class". The two types don't share statics or fakes.

Inheritance in MongoDb: how to request instances of defined type

This is how I used to utilize inheritance in Entity Framework (POCO):
ctx.Animals // base class instances (all instances)
ctx.Animals.OfType<Cat> // inherited class Cat's instances only
ctx.Animals.OfType<Dog> // inherited class Dog's instances only
This is the only similar way I found in MongoDb (MongoDb reference):
var query = Query.EQ("_t", "Cat");
var cursor = collection.FindAs<Animal>(query);
Note in the latter case I have to deal with discriminator ("_t") and hardcode my class name, that is not quite convenient and looks awful. If I miss the query I got an exception on enumeration attempt. Have I missed something? My suggestion was the document Db which stores objects 'as is' should handle inheritance easily.
Assuming your discriminators are functioning (_t is stored correctly for each document) then I think this is what you are looking for.
var results = collection.AsQueryable<Animal>().OfType<Cat>
Returns only those documents that are of type 'Cat'.
Well, a document db does in fact store objects "as is" - i.e. without the notion of objects belonging to some particular class. That's why you need _t when you want the deserializer to know which subclass to instantiate.
In your case, I suggest you come up with a discriminator for each subclass, instead of relying on the class name. This way, you can rename classes etc. without worrying about a hardcoded string somewhere.
You could do something like this:
public abstract class SomeBaseClass
{
public const string FirstSubClass = "first";
public const string SecondSubClass = "second";
}
[BsonDiscriminator(SomeBaseClass.FirstSubClass)]
public class FirstSubClass { ... }
and then
var entireCollection = db.GetCollection<FirstSubClass>("coll");
var subs = entireCollection.Find(Query.Eq("_t", SomeBaseClass.FirstSubClass));
From your link:
The one case where you must call RegisterClassMap yourself (even without arguments) is when you are using a polymorphic class hierarchy: in this case you must register all the known subclasses to guarantee that the discriminators get registered.
Register class maps for your base class and each one of your derived classes:
BsonClassMap.RegisterClassMap<Animal>();
BsonClassMap.RegisterClassMap<Cat>();
BsonClassMap.RegisterClassMap<Dog>();
Make sure that your collection is of type of your base class:
collection = db.GetCollection<Animal>("Animals");
Find using your query. The conversion to the corresponding child class is done automatically:
var query = Query.EQ("_t", "Cat");
var cursor = collection.Find(query);
If the only concern is hardcoding class name, you can do something like this:
collection = db.GetCollection<Animal>("Animals");
var query = Query.EQ("_t", typeof(Cat).Name);
var cursor = collection.Find(query);
Take a look on the documentation
http://docs.mongodb.org/ecosystem/tutorial/serialize-documents-with-the-csharp-driver/#scalar-and-hierarchical-discriminators
The main reason you might choose to use hierarchical discriminators is because it makes it possibly to query for all instances of any class in the hierarchy. For example, to read all the Cat documents we can write:
var query = Query.EQ("_t", "Cat");
var cursor = collection.FindAs<Animal>(query);
foreach (var cat in cursor) {
// process cat
}

XmlSerializer, XmlArray with dynamic content... how?

To start: This is also for REST deserialiaztion, so a custom XmlSerializer is out of the question.
I have a hjierarchy of classes that need to be serializable and deserializable from an "Envelope". It has an arrayelement named "Items" that can contain subclasses of the abstract "Item".
[XmlArray("Items")]
public Item [] Items { get; set; }
Now I need to add XmlArrayItem, but the number is not "fixed". We use so far reflection to find all subclasses with a KnownTypeProvider so it is easy to extend the assembly with new subtypes. I dont really want to hardcode all items here.
The class is defined accordingly:
[XmlRoot]
[KnownType("GetKnownTypes")]
public class Envelope {
but it does not help.
Changing Items to:
[XmlArray("Items")]
[XmlArrayItem(typeof(Item))]
public Item [] Items { get; set; }
results in:
{"The type
xxx.Adjustment
was not expected. Use the XmlInclude
or SoapInclude attribute to specify
types that are not known statically."}
when tyrying to serialize.
Anyone an idea how I can use XmlInclude to point to a known type provider?
The KnownTypesAttribute does not work for XmlSerializer. It's only used by a DataContractSerializer. I'm quite sure that you can exchange the serializer in WCF, because I have done that for the DataContractSerializer. But if that's not an option, you have to implement IXmlSerializable yourself and handle type lookup there.
Before disqualifying this solution: You just have to implement IXmlSerializable just for a special class which replaces Item[]. Everything else can be handled by the default serializer.
According to: http://social.msdn.microsoft.com/Forums/en-US/asmxandxml/thread/83181d16-a048-44e5-b675-a0e8ef82f5b7/
you can use different XmlSerializer constructor:
new XmlSerializer(typeof(Base), new Type[] { typeof(Derived1), ..});
Instead of enumerating all derived classes in the base definition like this:
[System.Xml.Serialization.XmlInclude(typeof(Derived1))]
[System.Xml.Serialization.XmlInclude(typeof(Derived2))]
[System.Xml.Serialization.XmlInclude(typeof(DerivedN))]
I think you should be able to use your KnownTypeProvider to fill the array in the XmlSerializer's constructor.

Resources