I am trying to figure out best way to model class inheritance in DocumentDb.
Say my classes are structured as
class A
property X
property Y
property Z
class B inherits from A
property W
Is there a built in support to handle this? If I use Lambda expressions in my client code, will they be able to distinguish between the types automatically?
Will the following query only return objects of type B back? Or will it also consider instances of base class A?
var bCollection = from o in client.CreateDocumentQuery<B>(collectionLink)
where X > 2
select o;
Is there a built in support to hand this? If I use Lambda expressions in my client code, will it be able to distinguish b/w the types automatically?
Yes, you can use lambda syntax in client side, as long as you specify the specific type in the generic method, as client.CreateDocumentQuery<YourType>(collectionLink).
Will following query only bring objects of type B back? Or will it also consider instances of base class A?
DocumentDB is a schemaless store and does not store type information. The overloaded generic methods provided in the client are syntactic sugar, to let you easily create queries.
All queries are evaluated against json documents, which do not have type information.
Inheritance scenario
So, if you fire a query for a property which is present only in your derived class, you will get values corresponding only to your derived class. But, if the property you are querying on is in both base class and derived class, you'll get back both results. For example, in your case filtering on W would give you results of only class B, but filtering on X, Y or Z would give you values for both classes A and B.
Classes with shared schema in same collection
Note that this does not just happen in the base-derived class scenario. Same behavior would happen if you have 2 separate classes, which do not inherit each other, but have a property with the same name. Querying on that property will return results of both classes.
For example, if you have 2 classes which are stored in the same collection:
class A1 { int x; }
class A2 { int x; }
Even if you form your query using the client.CreateDocumentQuery<A1>(collectionLink), results of both class A & B will be returned. As I mentioned earlier, the type specification in the client is just to make your life easier while forming the query.
I you want to be able to query different types of data, having shared schema elements, stored in the same collection - I would recommend having a separate property to store the type information manually and filtering on that property.
class DocumentDbData
{
string DataType;
DocumentDbData(string type) { DataType = type;}
}
class A1 : DocumentDbData
{
string x;
A1() : base("A1")
}
class A2 : DocumentDbData
{
string x;
A2() : base("A2")
}
The query, client.CreateDocumentQuery<A1>(collectionLink).Where(d => d.DataType == "A1" && d.x == "xvaluefilter") will now return only data for class A1.
I use node.js not .NET, so I don't recognize the CreateDocumentQuery<B> syntax. Is there a way to inspect the actual query that is sent by the .NET SDK to see if there is something added to the WHERE clause to restrict the results to type B? Alternatively, is there some field like _Type added to your documents without your intervention? I highly doubt the query clause you provided is so modified. I'm less sure that an _Type field isn't added, but I consider it less than 50% likely. My instinct is just that the <B> specification on the CreateDocumentQuery simply casts the returned objects to type B for you. I have no idea if that will cause an error if your result set included class A objects or if it will use null or some other default for missing fields.
Assuming all of the above, you'll probably have to model class hierarchy yourself. I have modeled this in two different ways:
Use a materialized array to indicate the entire class hierarchy for each document. So, ["Animal", "Mammal", "Cat"]. Then when you want all Mammals, you can query with WHERE "Mammal" IN c.class.
More recently, I've switched to having a separate field for each type that something is. So, isAnimal = true, isMammal = true, and isCat = true. This is more of a mixin approach, but you can still model class hierarchies this way.
Related
Say you have a class with members that are collections, such as.
public class Forest {
public IImmutableList<Tree> Trees { get; }
. . .
}
When I generate equality members with ReSharper, the collections do not compare correctly. The generated Equals() method, when comparing collections, uses public static bool Equals(object objA, object objB) defined in Object:
protected bool Equals(Forest other)
{
return Equals(Trees, other.Trees);
}
Shouldn't it use Enumerable.SequenceEqual(), like Trees.SequenceEqual(other.Trees)? Do I need to manually change the generated Equals() to use Enumerable.SequenceEqual(), or is there some better way that doesn't require modifying generated code?
ReSharper does not try to perform deep equality collection check on collection, since it has no idea how to do it for each and every collection type (and what exactly a "collection type" means?). Also, most of the mutable collection types are represented with complex objects (storing element equality comparers inside, for example), not the simple "values" (unlike immutable collections) that can be checked for equality easily.
Always generating Enumerable.SequenceEquals() is not a good idea most of the time, since it's operates over too abstract IEnumerable<T> interfaces - it does not even check the collections .Count to return false early. Also, some of set-like collections for the two equal sets do not guarantee the same order of elements when enumerating using IEnumerable<T> interface.
Some immutable collections have special APIs for equality comparison (strangely enough, ImmtableList has no such API, unlike ImmutableHashSet.SetEquals), but ReSharper has no special knowledge for such APIs. With all that in mind, we decided to stick with object.Equals() invocation generation, leaving the user with the ability to clarify intentions. Maybe we should produce comments in generated code clarifying this...
In your particular case, I suggest to compare .Count of ImmutableList first and use Enumerable.SequenceEquals() afterwards.
Given the following classes
abstract class SomeAbstractClass { abstract val name: String }
data class DataClass( override val name: String ) : SomeAbstractClass()
class NoDataClass( override val name: String ) : SomeAbstractClass()
For any instance of SomeAbstractClass, can I determine whether it is a data class without relying on type checking?
Some background: this seemed the best way of combining inheritance and data classes to me, as suggested in a different answer. Now, within the initializer block of SomeAbstractClass, I want to throw an exception in case the derived type is not a data class to ensure 'correct' (immutable) implementations of derived types.
Using reflection, the Kotlin class description (KClass) can be obtained using the ::class syntax on the instance you want to investigate (in your case, this::class in the initializer block of the abstract class). This gives you access to isData:
true if this class is a data class.
However, as Oliver points out, data classes can still contain var members, so you likely also want to check whether all member variables (and their member variables recursively) are defined as val to ensure immutability of all deriving classes.
I am using Immutable JS in conjunction with React + Redux. For the most part I really love how it reinforces the Redux paradigm, with the exception of its property accessor methods.
For Immutable Maps, one must access properties using the Immutable get method.
Ex. this.props.exampleMap.get('mapProperty');
However, for Immutable Records, there is no get method. Instead you just access properties with the dot method as with normal JS objects.
Ex. this.props.exampleRecord.recordProperty
My question is, why is there this discrepancy? This is making me a little OCD because my components are now filled with a mix of both methods and frankly it's a little ugly.
You actually can use .get(...) for immutable records. The way I think of is that records have additional nicer syntax by allowing you to access the properties directly.
If you take a look at the type definitions of a record, you'll see that record constructors create objects with types Immutable.Map<string, any>.
This nicer syntax is possible because you predefine the properties of the record upon creation.
Here is the immutable record creation example taken directly from their docs
const { Record } = require('immutable')
const ABRecord = Record({ a: 1, b: 2 })
const myRecord = new ABRecord({ b: 3 })
So remember, you give the Record function an object with default values and it returns a constructor you can use to create object with new.
I am trying to make a replacement VB6 class for the Scripting.Dictionary class from SCRRUN.DLL. Scripting.Dictionary has (among other things) a "Keys" method that returns an array of keys, and a read/write "Item" property that returns the item associated with a key. I am confused about this, because both of them seem to be defaults for the class. That is:
For Each X In MyDict
Is equivalent to:
For Each X In MyDict.Keys
Which to me implies that "Keys" is the default operation for the class, but:
MyDict("MyKey") = "MyValue"
MsgBox MyDict("MyKey")
Is equivalent to:
MyDict.Item("MyKey") = "MyValue"
MsgBox MyDict.Item("MyKey")
Which to me implies that "Item" is the default operation for the class.
I've never before created a VB6 class that had a default operation, so upon realizing this, I thought perhaps I could define multiple default operations as long as they all have different signatures, which they do: Keys is nullary, the Item getter takes a Variant, and the Item setter takes two Variants. But this doesn't seem to be allowed: When I use "Tools/Procedure Attributes" to set the Keys function to be the default, and then I use it to set the Item property to be the default, the IDE complains that a default has already been set.
So I think I'm misunderstanding something fundamental here. What is going on in the Scripting.Dictionary object that makes it able to act as if "Keys" is the default in some contexts, but as if "Item" is the default in others? And whatever it is, can I accomplish the same thing in VB6?
OK, answering my own question: I haven't tried this yet, but I gather that "Item" should be made the default, and that I should add an entirely new function called "NewEnum" that looks something like the following (slightly modified from an example in Francesco Balena's "Programming Microsoft Visual Basic 6.0" book):
Public Function NewEnum() As IUnknown
Set NewEnum = m_Keys.[_NewEnum]
End Function
(where "m_Keys" is a Collection containing the keys), and then use Tools/Procedure Attributes to hide NewEnum and to set its ProcID to -4.
What you are observing is the difference between the default member and a collection enumerator. A COM object (including VB6 classes) can have both.
You can identify the default property of a class by looking in the Object Browser for the tiny blue globe or the words "default member of" in the description (see Contents of the Object Browser). The Object Browser will not identify an enumerator method, but if you look at the class's interface definition using OLE View or TypeLib Browser (free but registration required) it's DispId will be 0xfffffffc or -4.
In your own class, you can mark the default property by setting the Procedure ID to "(default)" in the Procedure Attributes dialog (see Making a Property or Method the Default). You already listed the steps for setting up the collection enumerator in your own answer, but you can find this listed as well in the Programmer's Guide topic Creating Your Own Collection Class: The House of Bricks.
Scripting.Dictionary has a dirty secret:
It does not handle enumeration at all, it returns big ugly Variant arrays and your For Each loops iterate over those.
This is one of the reasons why a Dictionary can actually be far less efficient than a standard VB6 Collection.
In an ASP.NET MVC 4 application I get a JSON response from an external server that contains an array of "fields". Each field is of an individual type and contains an array of values of that type.
I'd like to deserialize that JSON either into a DynamicObject so that I can access the indivudual value propreties or I need some kind of a child class chooser which decides which class, derived from a "ValueBase" class, is needed to access the different properties of the individual value object.
I hope you know what I mean... it's a little bit complicating.
I've already tried to deserialize it into a DynamicObject (a class that derives from DynamicObject that is). But I get error messages when accessing that object's dynamic properties in the View that the properties I'd like to display don't exist.
So how does a class that derives from DynamicObject have to look like to accept and grant access to the individual differen "value"-properties provided by the JSON code?
And if that wasn't possible or the wrong way to go, how would I have to implement a suitable type chooser class?
Thanks a lot!
I've kinda solved it myself.
Instead of directly converting the returned JSON object (a JSON array to be more precise) into a specific class I fetch it as a dynamic and give it into the constructor of a class that contains a collection of instances of another class the object actually ought to be of (I get a JSON array returned from the webservice anyway). In the constructor of the collection class I decide depending on a value of the JSON object of which inherited class the new object is gonna be and put that into the collection. Yeah, I walked that way afoot somehow but it works.
Looks like this:
public CollectionClass(dynamic dyn)
{
foreach(var item in dyn.items) {
switch((string)item.external_id) { // might have used a Dictionary instead but...
case "member":
this._collection.Add(new Member(item));
break;
case "date":
this._collection.Add(new Date(item));
break;
default: break;
}
}
}
The Member-class itself contains a similar constructor which also requires a dynamic parameter. And it also "builds itself up" depending on values inside the item.
If there's any easier way or a "royal road" of achieving this I'd be grateful for any further advice.