Documentation



It's very importanxt that you understand the libraries used by RAW Framework otherwise you will only see the framework in action but you will not be able to modify the generated code or the templates to suit your needs, so please visit the prerequisites page and follow the links in that page.

 

The framework takes a solution template as an starting point for your application.


All other similar frameworks forces you to have your model in the same project that your website, with RAW Framework you can have a separated proyect with all your entities.

Another thing that makes RAW framework different, is the it can generate code automatically for N:N and 1:N relationships without any problems and lets you define how those relationships occur in the database. 

Quick tutorial

Before you begin, be sure to have all the prerequisites installed.
This is tutorial is based on the Contoso University tutorial by Microsoft.
The database from the Contoso University tutorial from Microsoft is a little bit different to the one that we are going to use for this tutorial, the main difference is on some data types and that we use views to represent Students and Instructors instead of letting Entity Framework to automatically filter the data

Our DB Schema is represented in the following image. A script to create the schema and sample data can be found here


Open a command prompt and navigate to a directory where your solution will be created, and run the following command:

rawc newApp

A name for your app will be asked, in this case we will use "ConUniv" as the name, remember that by default the scaffolding and the application is going to look for a database named as your solution's name on your local SQL Server Express instance, in this case is ConUniv, a folder with the same name as your application will be created and contains everything you need to start building your application. Type cd ConUniv and open the ConUniv.sln file with Visual Studio 2015 or open the folder ConUniv.Web with Visual Studio Code, this is the Solution structure that you will see:


To start scaffolding we need to generate the models for the tables and views that we will be using, type the following commands to do it:

  • rawc new:model[Course]
  • rawc new:model[Instructor]
  • rawc new:model[Student]
  • rawc new:model[Department]
  • rawc new:model[CourseInstructor]
  • rawc new:model[Enrollment]
  • rawc new:model[OfficeAssignment]

If you want to generate models for the whole database(only tables, not views) type the following command:

rawc new:full_db_models

Sometimes it's easier to generate all the models and then remove it the ones that you don't need.

If you navigate to your solution, you will notice that the models were added to the [ApplicationName].DataLayer project, under the Models folder.
Open one of the models, Department.cs for instance, and you will see that the model's properties have been decorated with some attributes,


Those decorators are used only when the UI is generated, so if you want to change them, do it before you generate the UI.

We will change a couple of them now, edit the Instructor and the Student files, we will replace the attributes added to the Discrimitator field, we don't want the user to edit that field, so we replace them with the Hidden attribute and we will make the property readonly, the property in both classes should look like this respectively:




For more information about all the available decorators go here.


At this point we could generate with the framework the controllers, repositories, views and javascript files that we need to have CRUD functionality for each one of the models, for isntance, the following command will generate all the code for the Course model:

rawc crudFor[Course]

Most of modern web applications use ajax to get and push data to the server but scaffolding solutions don't implement ajax calls, also many .Net code generators use helpers like HTML helpers or the new Tag helpers for the UI, Tag helpers was a huge improvement over HTML helpers but still are not enough for a few reasons:

  • The UI is technology dependant.
  • Harder interaction between designers and developers.
  • Page rendering is slower than pure html.
The views generated by RAW framework are just html, so it's technology independant and facilitates team work between designers and developers, page rendering is faster and finally, the views(and everything) are generated based on templates that can be modified easily.

Another important thing about RAW framework is, that when developing real applications it's very rare that UI will use only one table, ViewModels are very popular developing Asp.Net MVC applications but frameworks in general or code generator don't support them, but RAW does, also calls to access data are async calls so your application will be using the server resources more efficiently.
For this tutorial we are going to use ViewModels and generate the CRUD for it, but first we will need to generate the repositories, type the following commands to do it:

  • rawc new:repository[Course]
  • rawc new:repository[Instructor]
  • rawc new:repository[Student]
  • rawc new:repository[Department]
  • rawc new:repository[CourseInstructor]
  • rawc new:repository[Enrollment]
  • rawc new:repository[OfficeAssignment]

All the repositories were added to the [ApplicationName].DataLayer project, under the Repositories folder.

The repositories help us to interact with the database, we create a repository for each table or view that we want to interact with, repositories inherit from the RepositoryBase class and you can override any of it's methods if you need or you can modify the base class also.

At this point we can create our ViewModel, for convention we strongly suggest that all the ViewModels must be located in the [ApplicationName].BusinessLayer project, under the ViewModels folder.

Create these two ViewModels in the proper folder:




In the DepartmentViewModel we notice a few things:

  • The class is decorated with the NeedletailViewModel attribute. If this attribute is missing, the RAW framework generator will not work.
  • The class inherits from the ViewModelAutoLoadAndSaveAsync. This is to let RAW load and save data automatically.
  • The Department property is decorated with the Autocomplete attribute. This attribute tells the generator how that field will be populated in the UI, in this case an autocomplete functionality is used to enter the data.
More about ViewModels here.

We are ready to scaffold the ViewModels, type the following commands in the console:

  • rawc new:crudFor[InstructorViewModel]
  • rawc new:repository[DepartmentViewModel]
  • *Since we already created the Instructor and Department repositories we get a confirmation prompt to overwrite existing files.

Before run the app, we are going to make a couple of small adjustments on two methods inside the InstructorController class, this changes are only for a better UX.
If you remeber, we used the Autocomplete attribute in the DepartmentViewModel class, this attribute allows the user to select a record from a list of records that match a search criteria, in this example, the InstructorID field is filled with a search by the instructor's FirstName, we will make a small adjustment so the user can also search by the LastName, to do this we need to change the GetTextForAutocomplete and Search methods in the InstructorController class, the new version of the methods should look like this:



Run the app, on the home page you will see a couple of links to navigate to the Departments and Instructors generated functionality.



Go to Department list and edit one of the existing records, you will see comething like this:



Go to Instructor list and edit one of the existing records, you will see comething like this:

With a few small changes in a couple of minutes we can improve it like this:


Your application

Use RAW Framework as an starting point, we encourage you to modify the code and the templates to suit your needs. The templates used to generate everything are located under the Templatesfolder in the same folder that contains your solution.



RAWC Commands

This is the list of available commands and their usage.

  • rawc newApp
    This command will create a new Asp.Net MVC Core application from the RAW template.
  • rawc new:model[table name]
    This command will create a new model, the table must exists in your database, the model will be created with the same name as the table.
  • rawc new:full_db_models
    This command will create models from all the tables in the database, the table must exists in your database, the model will be created with the same name as the table.
  • rawc new:repository[model name]
    This command will create a new repository to interact with a table that should have the same name as the model name passed as parameter.
  • rawc new:controller[model name]
    This command will create a new controller with Create, Retrieve, Update and Delete actions for the model passed as parameter.
  • rawc new:view[model name,view type, true/false(use bs_grid)]
    This command will create a single view for the model passed as parameter, the available view types are:
    • create
    • edit
    • details
    • index
    The third parameter(the boolean) is only used when generating the index view, by default a html table is used, when this parameter is set to true the data is displayed using bs_grid a component that has pagination and sorting, as follows an example of how to use this parameter.
    rawc new:view[Instructor,index,true]
  • rawc new:crudFor[model name]
    This command will create everything that you need for CRUD operations for the model passed as parameter, this includes, repository, controller, views and javascript files.
  • rawc new:script[model name]
    This command will create all the javascript code needed by the views for the model passed as parameter.
  • rawc build
    This command will build the application.
  • rawc buildGen
    This command will build the Generator.
    * Use this command when you change the connection strings
  • rawc run
    This command will run the application on http://localhost:5000
  • rawc help
    Shows the help.


Models and ViewModels

A list of available attributes for models and ViewModels.

  • Attributes for Models

  • TableKey
    Use this attribute to indicate that the field is the primary key of the record.
  • Hidden
    Use this attribute to indicate that the field should be rendered as a hidden input.
  • Between
    Use this attribute to indicate that the field should only accept values between the given Min and Max values.
  • Email
    Use this attribute to indicate that the field should only accept valid email addresses.
  • GreatherThan
    Use this attribute to indicate that the field should only accept values greather than the given value.
  • LessThan
    Use this attribute to indicate that the field should only accept values less than the given value.
  • Length
    Use this attribute to indicate that the field should only accept text of the specific given length.
  • MaxLen
    Use this attribute to indicate that the field should only accept text up to the maximum given length.
  • MinLen
    Use this attribute to indicate that the field should only accept text with the minimum given length.
  • Phone
    Use this attribute to indicate that the field should only accept valid phone numbers. It uses US format, but the country can be set on javascript.
  • RegularExp
    Use this attribute to validate the text entry against the given regular expression.
  • Required
    Use this attribute to indicate that the field is required.
  • ZipCode
    Use this attribute to indicate that the field should only accept valid zip codes. It uses US format, but the country can be set on javascript.


  • Attributes for ViewModels

  • Catalog
    Indicates that the property(List) is a catalog that must be sent to the UI, the framework automatically loads all the records in the given table.
  • HasMany
    Use this attribute in the main entity that represent's the ViewModel to indicate that it has a 1:N relationship with the given table.
    The parameters let you specify the foreign key and the field that is used to make the relationship. HasMany(local list, foreign key, referenced table, referenced key)
    • local list: The name of the property in the ViewModel that holds the N records.
    • foreign key: The propertry in the model that is used as a foreign key.
    • referenced table: The name of the table where the N records are stored.
    • referenced key: The name of the field in the table that is used to make the relationship with the primary entity, in most of the cases should be the primary key.
  • HasManyNtoN
    Use this attribute in the main entity that represent's the ViewModel to indicate that it has a N:N relationship with the given table.
    A third table is needed to create this kind of relationship.
    The parameters let you specify the foreign key and the field that is used to make the relationship. HasManyNtoN(local list, foreign key, relation table, relation table foreign key, relation table referenced key, referenced table, referenced key)
    • local list: The name of the property in the ViewModel that holds the N records.
    • foreign key: The propertry in the model that is used as a foreign key.
    • relation table: The name of the table that is used to make the relationship between N and N.
    • relation table foreign key: The propertry in the model that stores the foreign key in the main entity.
    • relation table referenced key: The name of the field in tha table that is used to make the relationship, in most of the cases should be the primary key.
    • referenced table: The name of the table where the N records are stored.
    • referenced key: The name of the field in tha table that is used to make the relationship with the primary entity, in most of the cases should be the primary key.
  • HasOne
    Use this attribute in the main entity that represent's the ViewModel to indicate that it has a 1:1 relationship with the given table.
    HasOne(local object, foreign key, referenced table, referenced key)
    • local object: The name of the property in the ViewModel that holds the referenced record.
    • foreign key: The propertry in the model that is used as a foreign key.
    • referenced table: The name of the table where the N records are stored.
    • referenced key: The name of the field in the table that is used to make the relationship with the primary entity, in most of the cases should be the primary key.
  • Autocomplete
    Use this attribute to tell the framework to generate an autocomplete field.
    Autocomplete(foreign key, referenced table, referenced field, search field, display field, order by field)
    • foreign key: The propertry in the model that is used as a foreign key.
    • referenced table: The name of the table where the records to be searched are stored.
    • referenced key: The name of the field in the table that is used to make the relationship with the primary entity, in most of the cases should be the primary key, this field contains the value that is going to be stored in the main entity.
    • search field: The field that we want to search by.
    • display field: The field that we want to display in the search results, in most of the cases is the same as the search field.
    • order by field: The field that is going to be used to order the search results, in most of the cases is the same as the display field.
  • SelectFrom
    Use this attribute to tell the framework to generate a html Select control.
    SelectFrom(local list, foreign key, referenced table, referenced key, display field)
    • local list: The name of the property in the ViewModel that holds available options in the Select.
    • foreign key: The propertry in the model that is used as a foreign key.
    • referenced table: The name of the table where the available options records are stored.
    • referenced key: The name of the field in the table that is used to make the relationship with the primary entity, in most of the cases should be the primary key, this will be the option's value for the Select.
    • display field: The name of the field that will be displayed as available options in the Select


Data Access with Needletail

For this sample, we are going to use the Northwind database that can be downloaded from here.

These are going to be the models for the samples:

public class Order
{
      [TableKey(CanInsertKey = false)]
      public int OrderID { get; set;}
      public string CustomerID { get; set;}
      public int EmployeeID { get; set;}
      public DateTime OrderDate { get; set;}
      public DateTime RequiredDate { get; set;}
      public DateTime? ShippedDate { get; set;}
      public int ShipVia { get; set;}
      public decimal Freight { get; set;}
      public string ShipName { get; set;}
      public string ShipAddress { get; set;}
      public string ShipCity { get; set;}
      public string ShipRegion { get; set;}
      public string ShipPostalCode { get; set;}
      public string ShipCountry { get; set; }
}

public class OrderDetails
{
      public int OrderID { get; set; }
      public int ProductID { get; set; }
      public decimal UnitPrice  { get; set; }
      public int Quantity { get; set; }
      public float Discount { get; set; }
}

              

*The [TableKey] attribute indicates which field/property is the primary key in the database, you need to indicate if the primary key is  automatically created using the “CanInsertKey” variable.

To access the Orders table we need to instantiate an object indicating the connection string and the table.

var needleTailContext = new DBTableDataSourceBase<order, int >("connectionString", "Orders");
//Or 
using (var needleTailContext = new DBTableDataSourceBase<order, int >("connectionString", "Orders"))
{
    //the code to access the DB here
}
              

Using Needletail DataAccess

Samples of the most common methods:
* There are also methods to execute stored procedures and execute scalar.

//Get all rows
var orders = needleTailContext.GetAll();

//Get a single row
var order = needleTailContext.GetSingle( where : new { OrderID = 11072 });

//Get many rows
var ordersS = needleTailContext.GetMany(where: new { CustomerID_Like = "LIN" });
  
//More filters and ordering
var ordersS = needleTailContext.GetMany(where: new { CustomerID_Like = "INO", Or_CustomerID_StartsWith = "FR" }, orderBy: new { OrderDate = "DESC" });

//Adding a new row
var sNewO = new Order { CustomerID = "BONAP", EmployeeID = 4, OrderDate = DateTime.Now, RequiredDate = DateTime.Now.AddDays(20), ShipVia = 1, Freight = 120, ShipName = "12, rue des Bouchers", ShipCity = "Marseille", ShipPostalCode = "13008", ShipCountry = "France" };
sNewO.OrderID = needleTailContext.Insert(sNewO);
  
//Updating a row, use this when you want to update many rows or when don't want to update all the row's columns
needleTailContext.UpdateWithWhere(values: new { Quantity = 10 }, where: new { OrderID = 11065 });
//Use this when you want to update a single row with all its properties, this can only be used if you defined a TableKeyneedleTailContext.Update(currentOrder);

//Delete one or many rows
needleTailContext.Delete(where: new { OrderID = sNewO.OrderID });

//Joins, this returns a DynamicEntity objects, this is easy to use but has performance issues.
var items = needleTailContext.Join("Orders.OrderID,Orders.CustomerID,Orders.OrderDate,[Order Details].ProductID,[Order Details].UnitPrice,[Order Details].Quantity","Inner Join [Order Details] on Orders.OrderID = [Order Details].OrderID AND Orders.CustomerID like '%INE%'", string.Empty,string.Empty, null);

//Joins using typed entities(user defined classes), this way is very fast but you need to define classes.
var items = needleTailContext.JoinGetTyped<orderdetailsjoin>("Orders.OrderID,Orders.CustomerID,Orders.OrderDate,[Order Details].ProductID,[Order Details].UnitPrice,[Order Details].Quantity","Inner Join [Order Details] on Orders.OrderID = [Order Details].OrderID AND Orders.CustomerID like '%INE%'", string.Empty,string.Empty, null);
              

All the methods have their Async version and a few overloads.

Filters for queries

The following are prefixes and suffixes that you can add to the field name in the where

  • _EndsWith example:var ordersS = needleTailContext.GetMany(where: new { CustomerID_EndsWith = "LIN" });
  • _StartsWith example:var ordersS = needleTailContext.GetMany(where: new { CustomerID_StartsWith = "ABC" });
  • _MoreThan example:var ordersS = needleTailContext.GetMany(where: new { UnitPrice_MoreThan = 10 });
  • _LessThan example:var ordersS = needleTailContext.GetMany(where: new { UnitPrice_LessThan = 5 });
  • _Like example:var ordersS = needleTailContext.GetMany(where: new { CustomerID_Like = "LIN" });
  • _Not example:var ordersS = needleTailContext.GetMany(where: new { City_Not = "Seattle" });
  • And_ example:needleTailContext.GetMany(where: new { CustomerID_Like = "INO", And_CustomerID_StartsWith = "FR" })
  • Or_ example:needleTailContext.GetMany(where: new { CustomerID_Like = "INO", Or_CustomerID_StartsWith = "FR" })
  • In_ example: needleTailContect.GetMay(where : new {CustomerID_In = new string[] {"KEY1","KEY2"} } );
*By default all the filters are concatenated with an AND clause.


Back