Entity Types

[This content is no longer valid. For the latest information on "M", "Quadrant", SQL Server Modeling Services, and the Repository, see the Model Citizen blog.]

An entity is an intrinsic type in the Microsoft code name “M” modeling language. An entity is a set of zero or more fields, which are named values.

An entity appears similar to a collection of elements, except that each of the elements has an identifier. You can access an element of an entity by its assigned name.

Entity types can have identity. The fields of an entity type can be assigned default values and the values can be constrained with expressions. The names of all fields must be distinct.

Entity Value Initializers

Entity values are created by using an entity initializer. Here is a simple entity value.

{ X => 100, Y => 200 };

This entity value has two fields: one named X with the value of 100, the other named Y with the value of 200.

Member Names

The name of a member can be arbitrary Unicode text. When a name violates the requirements of “M” identifier restrictions (for example, by including spaces, or the dot symbol), it is escaped with bracket symbols, as seen in the following example.

{ [Horizontal Coordinate] => 100, [Vertical.Coordinate] => 200 };

If the member name matches the identifier pattern, it can be written with or without the surrounding brackets, as seen in the following example.

HelloWorld => 1     // matches the identifier pattern
[Hello World] => 1  // does not match identifier pattern – escape it
_HelloWorld => 1    // matches the identifier pattern
A => 1              // matches the identifier pattern
[A] => 1            // matches the identifier pattern – brackets optional
[1] => 1            // does not match identifier pattern – escape it

Within a given entity, each member must have a unique name. That makes the following entity initializer illegal because it attempts to name two members with the same name X.

{ X => 100, X => 200 };

Entity Values

“M” imposes no limitations on the values of entity members. It is legal for the value of an entity member to refer to another entity.

Entity members can also refer to a collection. The following example shows an entity whose first field is the collection LotteryPicks.

Stats = {{ LotteryPicks { 1, 18, 25, 32, 55, 61 }, Odds => 0.00000001 }};

The following example shows an entity whose second member, Path, is a collection of entity values.

    r => { 
            Color => "Red",
            Path {
                    { X => 100, Y => 100 },
                    { X => 200, Y => 200 },
                    { X => 300, Y => 100 },
                    { X => 300, Y => 100 },
                }
       };

Entity initializers are syntactically similar to collection initializers, but you cannot mix named and unnamed elements in a single initializer. So the following is not allowed.

bad => {{ 1, X => 2, 3, Y => 4 }};

Entity Value Operators

Entity initializers are used to construct new entity values. “M” defines the . operator over entities for accessing the value of a given member. For example, this expression yields the value of the X member, which in this case is one hundred.

{ X => 100, Y => 200 }.X

The result of the dot operator is just a value that is subject to subsequent operations. For example, this expression yields the value 200.

{ Center { X => 100, Y => 200 }, Radius => 3 }.Center.Y

Entity Type Declarations

An entity type declaration describes the entity’s required members. The members of an entity type can be declared either as fields or as computed values. The value of a field is stored when an extent of the entity’s type is created; the value of a computed value is calculated and exists only in memory.

Most entity types declare multiple members, with the type ascribed explicitly. The following example requires that the X and Y members of NumericPoint be of type Integer32.

type NumericPoint 
{
     X : Integer32;
     Y : Integer32;
}

Note the use of type ascription syntax (“:”) to assert that the value of the X and Y fields must conform to the type Integer32. Given this definition, the following expressions all evaluate to true.

{ X => 100, Y => 200 } in NumericPoint
{ X => 100, Y => 200, Z => 300 } in NumericPoint 
! ({ X => true, Y => "Hello, world" } in NumericPoint)
! ({ X => 0, Y => 0 } in NumericPoint)

The “M” language is not an object-oriented language. One consequence is that a value can belong to multiple types that have no hierarchical relationship to each other. For example, define the following additional type.

type Point 
{ 
   X; 
   Y; 
}

The value { X => 100, Y => 200 } satisfies the definition of both NumericPoint and Point, so belongs to both types.

Field Type Ascription

It is not necessary to explicitly ascribe types to the fields in an entity type declaration. The following type definition describes the set of entities that contain at least fields named X and Y, irrespective of the values of those fields.

type Point 
{ 
   X; 
   Y; 
}

Given the preceding declaration, the following type tests all evaluate to true.

{ X => 100, Y => 200 } in Point
{ X => 100, Y => 200, Z => 300 } in Point // more fields than expected OK
! ({ X => 100 } in Point)               // not enough fields – not OK
{ X => true, Y => "Hello, world" } in Point

Thus the Point type does not constrain the values of the X and Y fields; any value is allowed.

Entity Types with 0 Members

An entity can contain zero members, so the following is the simplest possible entity type.

type MyEntity : Language.Entity;

This entity type does not declare any fields. In “M”, entity types are open in that entity values that conform to the type may contain fields whose names are not declared in the type. That means that the following type test evaluates to true.

{ X => 100, Y => 200 } in MyEntity

Identity

When you have a collection of entities, you usually must be able to point to a specific one. For example, you might need to identify which customer an address refers to. Even when you have an extent that only contains one entity, you might need to refer to it. For example, you might have an entity that describes a system’s configuration, and need to refer to it to make run-time decisions.

To reference an entity from another entity or value, the entity must have an identity field, which is specified by the identity constraint.

The identity constraint controls the representation of identity. If it is specified, the selected fields are used to represent the identity. If no identity constraint is specified, the entity cannot be referenced. Placing the identity constraint on a field implies that field can only be initialized. It cannot be updated.

The identity constraint may be specified either on entity declarations or on extent declarations, but not both. The identity constraint requires that the elements in the constraint are unique within each extent (but not across extents) as with the unique constraint. An entity declaration on a derived type supersedes that of any types it derives from. As a result, there can be only one identity constraint on an entity or an extent. Consider the following example.

module Entities
{
    type Container 
    {
        Id : Integer32;
        Capacity: Integer32;
    } where identity Id;

    CoffeeCups : {Container*} { {Id => 1, Capacity => 12} };
    WaterBottles : {Container*} { {Id => 1, Capacity => 12} };

    EqualityTest() {
        from c in CoffeeCups
        from w in WaterBottles
        where c == w
        select "Never"
    }
}

It is legal for the two extents to contain instances whose Id fields are equal. Having the same Id field does not equate the instances. The computed value EqualityTest always returns the empty collection because identity is relative to an extent.

Operators

The equality operations on entities compare identity (shallow equal). == returns true if both operands refer to an instance with the same identity in the same collection.

Members

The FieldNames() : Text*; member is defined on all entities. FieldNames() returns the string names of each label in an instance. This member is not affected by interpretation and does not return names of computed values or missing default values.

See Also

Concepts

Declaring Fields
Identity ("M" Programming Guide)
identity ("M" Keywords)
unique ("M" Keywords)

Other Resources

Constraints ("M" Programming Guide)