Table of Contents

you are here (click to zoom) - discover the stack

Strictly Typed Data Models Guide (new v17.02)

In 2sxc 17 we introduced a new way to work with data, using compiled, strictly typed data models.

This guide should you understand how this works, how to use it, and how to handle various situations.

To Document

  1. How to extend the class
  2. How to use Services (todo - separate page)

Example Using a Typed Model

@inherits Custom.Hybrid.RazorTyped
@using AppCode.Data

@{
  // Wrap the data into a strong-typed AppCode.Data.Link object
  var links = AsList<Link>(MyItem);
}

@foreach (var link in links) {
  <a href="@link.Url">@link.Title</a>
}

How This Works

The above example uses a strong-typed model called Link which is defined in the AppCode.Data namespace. This model is a simple class which inherits from Custom.Data.Item16. It implement ITypedItem, so it supports all the commands such as .IsEmpty(...) or .String(...).

Usually the class is auto-generated by the 2sxc Copilot. But you can also create it manually, OR extend the class to do more than what is auto-generated. What's important is that when auto-generated, it will have a property for each data-field in the content-type. This is why you can also write @link.Url and @link.Title in the example above.

What's great is that the generated code also has intellisense support, so the developer in VS Code will be guided and see tips / instructions on every property.

Basic How To Use and Access Properties

The properties in the strong-typed model are usually simple properties, so you can use them like this:

using AppCode.Data;

// Convert MyItem into a single strong-typed Product object
var product = As<Product>(MyItem);

var title = product.Title;          // title as string
var price = product.Price;          // price as decimal

// Links to URLs, Pages and Files / Images
var page = product.Page;            // url as string, terms like `page:72` will be resolved
var page2 = product.String("Page"); // url as string, terms like `page:72` will not be resolved

var imageUrl = product.Image;       // image as string-url, terms like `file:123` will be resolved
var image2 = product.String("Image"); // image as string, terms like `file:123` will not be resolved

var imageFile = product.ImageFile;  // image as IFile, terms like `file:123` will be resolved
var imageFolder = product.ImageFolder; // image as IFolder, may contain 0 or more files and folders

// Related Items
var cat1 = product.Category;        // App.Data.Category (if the content-type was configured correctly)
var cat2 = product.Category;        // ITypedItem (if the content-type was NOT configured correctly)

var cats1 = product.Categories;     // IEnumerable<Category> (if the content-type was configured correctly)
var cats2 = product.Categories;     // IEnumerable<ITypedItem> (if the content-type was NOT configured correctly)

Since the properties are real class properties, you can also use them in LINQ queries, like this:

// Sort the products by the Color A-Z
var productsSorted = products.OrderBy(p => p.Color).ToList();

// Get the first product
var firstProduct = products.FirstOrDefault();

Conversions, Lists and Mocking

This assumes that you have generated the data models using the Copilot. We'll try to cover all common use cases using code samples. These code samples assume you're working in Razor which inherit from Custom.Hybrid.RazorTyped. It's similar for C# files inheriting from Custom.Hybrid.CodeTyped.

// Use the Namespace
using AppCode;
using AppCode.Data;

// Convert any item into a single strong-typed object
// Will return null if the item is null
// Or throw an error if the item is not of the correct type
var product = As<Product>(MyItem);

// Convert any item into a single strong-typed object
// Will use the alternative if the item is null
var product = As<Product>(maybeNull) ?? alternative;

// Convert any item into a single strong-typed object
// Will return an empty Product object if the item is null
var product = As<Product>(maybeNull, mock: true);

// Convert any item into a single strong-typed object
// Will wrap the item to simulate a strong-typed object
var product = As<Product>(new { Title = "hello", Color = "green" }, mock: true);

// Convert any item into a list of strong-typed objects
// Use a mock object as fallback
var products = AsList<Product>(maybeNull)
  ?? As<Product>(new { Title = "hello", Color = "green" }, mock: true);

// convert a list of items into a list of strong-typed objects
var products = AsList<Product>(MyItems);

// Get all products from App Data - short and long example (internally identical)
var allProducts = AsList<Product>(App);
var allProducts = App.Data.GetAll<Product>(); // WIP - probably better to understand
var allProducts = AsList<Product>(App.Data.GetStream("Products"));

// Get all the products from a query (default stream)
var greenProducts = AsList<Product>(App.GetQuery("GreenProducts"));

// Get all the products from a query (specific stream)
var prodsInCategory = AsList<Product>(App.GetQuery("CategoryDetails").GetStream("Products"));

Advanced Initialization when Converting

Data Models can't have a constructor, since the object will be created internally. But in case your data model needs some special initialization, you can do it like this:

namespace AppCode.Data
{
  partial class Product
  {
    // Set this on Init
    public bool UserIsAdmin { get; set; }
    public string SpecialColor => UserIsAdmin "gold" : Color;
  }
}

And in the Razor/C# file which needs this

// single item
var product = As<Product>(MyItem);
product.UserIsAdmin = MyUser.IsSiteAdmin;

// list of items
var products = AsList<Product>(MyItems)
  .Select(p => { p.UserIsAdmin = MyUser.IsSiteAdmin; return p; })
  .ToList();

Handing Over to Razor Files

The caller would do

@Html.Partial("Details.cshtml", new { product, category, suggestion = otherProduct })

The Details.cshtml would then look like this:

@{
  var product = MyModel.Get<Product>("Product");
  var category = MyModel.Get<Category>("Category");
  var suggestion = MyModel.Get<Product>("Suggestion");
}

Extending the Class

todo

The properties are strong-typed

History

  1. Introduced in 2sxc v17.02