Skip to content

Entities (Specific)

nairdo edited this page Apr 24, 2013 · 10 revisions

Below is a breakdown of the significant, common, reusable entities that exist in Rock. They are listed below in logical groupings.

Category

This is a hierarchical structured set of categories, and therefore they are best viewed using a tree view control (see Rock:CategoryPicker). Categories are tied to a particular EntityType so each EntityType can have it's own category tree. Several features in Rock use categories including Workflow, PrayerRequests, DataViews, and Reports.

DefinedType & DefinedValue

You can think of DefinedTypes as a kind of dictionary of possible values for a particular thing. The particular thing is the 'defined type'. In Rock, developers can define types of reusable fields and their possible values using this generic entity (DefinedType and DefinedValue; stored in the respective tables of the same name). For example, there is a well-known DefinedType called Record Type which has the following DefinedValues: Person and Business. There is another type called Record Status which has these values: Active, Inactive, and Pending.

DefinedTypes are named, have a description, can have a category, can be ordered, and can also be further specified by a FieldType. DefinedValues are named, can have a description, and be ordered.

Instead of having to create many miscellaneous entities and tables to hold these various dictionary-lookup values, developers can simply rely on DefinedTypes in the Rock framework to manage this data.

To get a defined value when the only the id or guid is known, use the DefinedValueCache.Read() method.

  var statusDefinedValue = DefinedValueCache.Read( definedValueId );

  // the Name property holds the name of the defined value's 'value'
  string status = statusDefinedValue.Name;

There are several reusable UI controls in the UI Toolkit that can be used to bind and display DefinedType's DefinedValues. See Databinding Rock Lists for details.

NOTE: By convention, any entity that has a property that ends with *ValueId is a reference to a DefinedValue.

Device

Devices are things like check-in kiosks, giving kiosks, printers, etc. and they are categorized as such by their DeviceType property (which is a particular DefinedValue).

Devices can be geo-tagged with a GeoPoint and a GeoFence. The GeoPoint should be thought of as a single latitude and longitude that represents where the kiosk is positioned. The GeoFence is a collection of points (latitude and longitude) that forms a polygon which represents the zone where your device is enabled. Kiosks with GeoFences are used by the check-in system. People using their mobile phone to check-in will be tied to the kiosk if they are within the GeoFence of that kiosk.

Some Gory Details About Spatial Data & Geo-coding

The GeoPoint and GeoFence are both DbGeography datatype in C# and geography datatypes in SQL.

If you need a quick and dirty polygon around a particular point you can use this trick. Both the Buffer() method on the DbGeography datatype and the BufferWithTolerance() on the SQL geography datatype work similarly. Here is an example showing how it's done with SQL:

  DECLARE @point geography, @fence geography;
  SET @point  = geography::STGeomFromText('POINT(-122.34900 47.65100)', 4326);
  -- a distance of 600 meters with a tolerance of 10 creates roughly a 20 point polygon
  SET @fence = @point.BufferWithTolerance(600, 10, 0);

  -- output is a point and a 20 point polygon
  -- POINT (-122.349 47.651) |  POLYGON ((-122.34901206196022 47.650996196492137, -122.348...))  
  SELECT @point.ToString(), @fence.ToString()

Note the second parameter in the BufferWithTolerance is the tolerance specifier. If you wanted fewer points in your polygon you would increase tolerance. Using a value of 100 in the above example drops the number of points to seven (7).

The STBuffer() method will better approximate a circle because it specifies a much smaller tolerance. Doing that will come at a higher cost when it comes time to perform spatial calculations.

  DECLARE @point geography, @fence geography;
  SET @point  = geography::STGeomFromText('POINT(-122.34900 47.65100)', 4326);
  SET @fence = @point.STBuffer( 600 );

GeoPoint Inside the GeoFence?

How do you find if a point (DbGeometry) is inside your fence polygon (DbGeometry)? Good question. I believe you should use the Intersects() method which states: Determines whether this DbGeography value spatially intersects the specified DbGeography argument. That's pretty vague, but it does say spatially.

If you look at the EF source code for the Intersects method, you'll see they defer the calculation to the provider. So it's the responsibility of the provider -- and that's code I can't find in order to verify my assumptions.

So I created some unit tests. Inside the DeviceTests class are two tests which correctly pass when using the Intersects method to check if a point is either inside or outside a fence/polygon.

[Test]
public void ShouldFallWithinGeoFence()
{
    var deviceWithGeoFence = BufferedDeviceAtCCV();

    // (point near CCV parking lot about 400 meters from the CCV point above)
    var aLat = "33.70836";
    var aLon = "-112.20765";
    var aPointInside = DbGeography.FromText( string.Format( "POINT({0} {1})", aLon, aLat ) ); // NOTE: long, lat

    Assert.True( aPointInside.Intersects( deviceWithGeoFence.GeoFence ) );
}

[Test]
public void ShouldFallOutsideGeoFence()
{
    var deviceWithGeoFence = BufferedDeviceAtCCV();

    // (a point about half a mile away from CCV)
    var farLat = "33.6961";
    var farLong = "-112.2030";
    var aPointOutside = DbGeography.FromText( string.Format( "POINT({0} {1})", farLong, farLat ) ); // NOTE: long, lat

    // This point should NOT intersect our buffered CCV location
    Assert.False( aPointOutside.Intersects( deviceWithGeoFence.GeoFence ) );
}

FieldType

See Custom Field Attributes and FieldTypes.

Location

TODO

NoteType & Note

Notes (and NoteType) are generic, reusable entities in Rock. You can create entries for your own custom NoteTypes which are related to your custom entities. For example, the Prayer system created a "Prayer Comment" type of note which is tied to the Rock.Model.PrayerRequest entity. This is how people's comments are tied to prayer requests.

You are probably asking, 'I see how to related a Note to it's related entity (via the NoteType) but how does the actual note get related to the person who created it?' I have no idea.

David?

Clone this wiki locally