четверг, 5 сентября 2013 г.

Как подключиться к Teradata из MS Visual Studio

Я убил много времени на этот пустяк, с Oracle все получилось без проблем.
Я опишу два способа:
1) Через ODBC.
Скачиваем Teradata Client, устанавливаем и настраиваем наш ODBC источник (системный).
Проверить можно через Teradata SQL Assistant.
В нашем проекте добавляем

 
using System.Data.Odbc;


и добавляем:

 
string queryString = "insert into  TABLE values(1,1,1,1,1,1,'2013-09-04')";



            OdbcCommand command = new OdbcCommand(queryString);



            using (OdbcConnection connection = new OdbcConnection("Dsn=ODBCname;uid=user_id;Pwd=password;"))

            {

                command.Connection = connection;

                connection.Open();

                command.ExecuteNonQuery();

 
}
2) Через Teradata.Client.Provider
Добавляем в References данную сборку из клиента Teradata.
 using Teradata.Client.Provider;

Далее:
  
                TdConnectionStringBuilder conBuilder = new TdConnectionStringBuilder();
                conBuilder.DataSource = "host";
                conBuilder.Password = "pass";
                conBuilder.UserId = "user";
                
                conBuilder.Database = "DBName";
                conBuilder.SessionMode = "TERADATA";
                conBuilder.AuthenticationMechanism = "SPNEGO";
                conBuilder.SessionCharacterSet = "UTF8";
                TdConnection connection = new TdConnection();
                connection.ConnectionString = conBuilder.ConnectionString;
                connection.Open();
SPNEGO должен быть включен в Teradat-е, по умолчанию он выключен.

воскресенье, 1 сентября 2013 г.

Паттерн стратегия

Здесь я хотел бы рассказать о паттерне стратегии.

В качестве примера, рассмотрим следующий класс:
    abstract class Duck
    {
        public void quack()
        {
            Console.Out.WriteLine("Quack!");
        }

        public void swim()
        {
            Console.Out.WriteLine("Bulk!");
        }

        abstract public void display();
    }

     Это наш класс Утка, которая умеет крякать и плавать, при этом все утки, которые наследуют этот класс умеют тоже самое. Метод display у нас является абстрактным, так как каждая утка имеет свой образ и требует конкретной реализации.
Ниже я показал диаграмму классов (у нас две новых утки: MallarDuck и RedHeadDuck, которые наследуют абстрактный класс Duck):



Класс MallarDuck:

using System;

    class MallarDuck : Duck
    {
        public override void display()
        {
            Console.Out.WriteLine("I am Mallar Duck!");
        }
    }

Класс RedHeadDuck:

using System;
   class RedHeadDuck : Duck
    {
        public override void display()
        {
            Console.Out.WriteLine("I am Red Head Duck!");
        }
    }
Запускаем наш первый пример:
using System;

    class Program
    {
        static void Main(string[] args)
        {
            MallarDuck  MyDuckMallar = new MallarDuck();
            RedHeadDuck MyDuckRedHead = new RedHeadDuck();
            
            MyDuckMallar.display();
            MyDuckRedHead.display();
            
            MyDuckMallar.quack();
            MyDuckRedHead.quack();

            Console.In.ReadLine();

        }
    }

Результатом запуска будет:

Какие проблемы сразу видны?
    Если мы заходим дать возможность нашим уткам летать, то необходимо будет добавить в наш абстрактный класс Duck метод fly(), при этом его конкретную реализацию унаследуют все классы, т.е. даже те утки, которые не должны летать. Для них нам придется переписывать данный метод и делать его пустым (например деревянная утка не должна уметь летать). При добавлении других возможностей в будущем, каждый  раз придется реализовывать пустые методы.

Какой Выход?
    Возможно, стоит вынести метод fly() в интерфейс? Тогда мы достигним того, что деревянная утка не должна летать, так как она не будет реализовывать интерфейс метода fly().
Но тут возникает другая проблема: дублирование кода. Так как интерфейс не может содержать конкретную реализацию метода, то нам придется реализовывать метод fly() для каждого класса. При каких-либо изменениях, необходимо будет внести их в каждый класс.

Основным принципом проектирования является: Выделить части приложения, которые могут изменяться и отделить их от тех, которые являются постоянными. Иными словами нам нужно выделить изменяющийся код так, чтобы не изменять постоянную часть в дальнейшем.

Принцип проектирования: Программируйте на уровне интерфейсов.

Руководствуясь этими двумя принципами переделаем наш пример.
 Мы знаем, что метод fly() может быть не у всех субклассов класса Duck, поэтому нам необходимо выделить его в отдельный набор классов, так же как и метод кряканья quack().
Руководствуясь первый принципом мы должны создать интерфейс для методы fly()

Получаем следующую диаграмму классов:


Давайте посмотрим на изменившийся класс Duck:


    abstract class Duck
    {
        //переменные интерфейсов, 
        //через которые будет происходит делегирование действий
        protected IFlyBehavior flyBehavior;
        protected IQuackBehavior quackBehavior;

        //создаем динамическое изменение поведения уток
        public void setFlyBehavior(IFlyBehavior fb)
        {
            flyBehavior = fb;
        }

        public void setQuackBehavior(IQuackBehavior qb)
        {
            quackBehavior = qb;
        }

        public void performQuack()
        {
            quackBehavior.quak(); //делегируем
        }

        public void performFly()
        {
            flyBehavior.fly(); //делегируем
        }

        public void swim()
        {
            Console.Out.WriteLine("Bulk!");
        }

        abstract public void display();
    }

Мы вынесли методы полета и кряканья в интерфейсы, а также сделали набор классов, которые являются реализацией разных алгоритмов полета и кряканья наших уток. Далее мы объявили две переменных в абстрактном классе Duck()
  protected IFlyBehavior flyBehavior;
  protected IQuackBehavior quackBehavior;
Которые ссылаются на классы, реализующие данные методы. Т.е. мы можем присвоить любой алгоритм кряканья или полета. Вызов делегирование происходит через методы:
        public void performQuack()
        {
            quackBehavior.quak(); //делегируем
        }

        public void performFly()
        {
            flyBehavior.fly(); //делегируем
        }
С помощью двух сеттеров мы можем динамически на лету присваивать разные алгоритмы нашим классам. Метод display() мы оставили абстрактным, так как для каждой утки он будет разным, а метод swim() для всех будет одинаков. Ниже приведу описание остальных классов:
    //интерфейс метода Полета
    interface IFlyBehavior
    {
        void fly();
    }
   // интерфейс метода кряканья
    interface IQuackBehavior
    {
        void quak();
    }
  //класс, реализующий невозможность летать
  class FlyNoWay: IFlyBehavior
    {
        public void fly()
        {
            Console.Out.WriteLine("I can not fly!");
        }
    }
  //Класс, реализующий алгоритм полета ракеты
  class FlyRocket: IFlyBehavior
    {
        public void fly()
        {
            Console.Out.WriteLine("I fly as rocket!");
        }
    }
  //Класс, реализующий алгоритм обычного кряканья
  class Quack : IQuackBehavior
    {
        public void quak()
        {
            Console.Out.WriteLine("quack!");
        }
    }
  //Класс, реализующий алгоритм бесшумного кряканья
 class MuteQuack: IQuackBehavior
    {
        
        public void quak()
        {
            Console.Out.WriteLine("Empty Quack!");
        }
    }
}
  //Класс дикой утки 
  public MallarDuck()
        {
            quackBehavior = new Quack();
            flyBehavior = new FlyRocket();
        }

        public override void display()
        {
            Console.Out.WriteLine("I am Mallar Duck!");
        }
    }
  //Класс красноголовой утки
  class RedHeadDuck : Duck
    {
        public RedHeadDuck()
        {
            quackBehavior = new Quack();
            flyBehavior = new FlyRocket();
        }
        public override void display()
        {
            Console.Out.WriteLine("I am Red Head Duck!");
        }
    }

Давайте теперь сделаем класс деревянной утки, для этого сделаем класс-модель утки, которая по умолчанию не умеет ничего делать:
   class ModelDuck : Duck
    {
        public ModelDuck()
        {
            quackBehavior = new MuteQuack();
            flyBehavior = new FlyNoWay();
        }

        public override void display()
        {
            Console.Out.WriteLine("I am model!");
        }
    }
Теперь давайте вызовем все наши классы, а также посмотрим как можно динамически изменять алгоритмы:
class Program
    {
        static void Main(string[] args)
        {
            MallarDuck  MyDuckMallar = new MallarDuck();
            RedHeadDuck MyDuckRedHead = new RedHeadDuck();
           
            //Наша дикая утка
            MyDuckMallar.display();
            MyDuckMallar.performFly();
            MyDuckMallar.performQuack();
            
            //красноголовая утка
            MyDuckRedHead.display();
            MyDuckRedHead.performFly();
            MyDuckRedHead.performQuack();
            
            //модель утки, которой мы поменяли алгоритм 
            //кряканья и алгоритм полета
            ModelDuck myThreeDuck = new ModelDuck();
            myThreeDuck.display();
            myThreeDuck.performFly();
            myThreeDuck.performQuack();

            myThreeDuck.setFlyBehavior(new FlyRocket());
            myThreeDuck.setQuackBehavior(new Quack());

            myThreeDuck.performFly();
            myThreeDuck.performQuack();

            Console.In.ReadLine();

        }
    }

Вот это да! Мы смогли избавиться от дублировния кода, теперь мы можем независимо разрабатывать алгоритмы и присваивать их любым уткам, а также мы смогли уйти от наследования, которое принудительно добавляло все методы во все субклассы!

Подобные связи между двумя классами называются композицией, т.е. поведение не наследуется, а предоставляется правилами выбора.

Принцип проектирования: Отдавайте предпочтение композиции перед наследованием.

Композиция позволяет не только инкапсулировать семейство алгоритмов, но и изменять поведение во время выполнения.
Паттерн СТРАТЕГИЯ определяет семейство алгоритмов, инкапсулирует каждый из них и обеспечивает их взаимозаменяемость. Он позволяет модифицировать алгоритмы независимо от их использования на стороне клиента.

четверг, 1 августа 2013 г.

ORACLE PL/SQL LONG TO VARCHAR2

ORACLE PL/SQL LONG TO VARCHAR2


Вот способ который я нашел в интернете, скорее всего он старый (для 8 оракла я такое уже видел), но делать нечего.

Перевод в LONG:

CREATE OR REPLACE Function convert_long_to_char( pTableName in varchar2,
                                                 pColumnName in varchar2,
                                                 pRowId in rowid ) return varchar2 As
      vCursor    integer default dbms_sql.open_cursor;
      vN         number;
      vLongVal  varchar2(4000);
      vLongLen  number;
      vBuflen    number := 4000;
      vCurPos    number := 0;
   begin
     dbms_sql.parse( vCursor,'select ' || pColumnName || ' from ' || pTableName ||
                                                             ' where rowid = :x',
                     dbms_sql.native );
     dbms_sql.bind_variable( vCursor, ':x', pRowId );
   
     dbms_sql.define_column_long(vCursor, 1);
     vN := dbms_sql.execute(vCursor);
   
     if (dbms_sql.fetch_rows(vCursor)>0) then
       dbms_sql.column_value_long(vCursor, 1, vBuflen, vCurpos ,
                                  vLongVal, vLongLen );
     end if;
     dbms_sql.close_cursor(vCursor);
     return vLongVal;
   end convert_long_to_char;
  /

Собственно насильно режется лонг до 4000 символов.

среда, 31 июля 2013 г.

СРЕДА ВЫПОЛНЕНИЯ .NET FRAMEWORK

1. СРЕДА ВЫПОЛНЕНИЯ .NET FRAMEWORK

   Средой выполнения является CLR (Common Language Runtime) - общеязыковая среда выполнения. Общеязыковая - это значит, что можно писать и на C# и С/С++ и Visual Basic, можно даже свой язык создать и свой компилятор для CLR). Общие механизмы работы этой среды подходят для всех языков программирования, которые ее используют.
 Все языковые компиляторы (CLR-совместимые компиляторы) генерируют IL-код и метаданные (управляемый модуль - PE  файл), с которым в последствии работает CLR.

Сам управляемый модуль состоит из:

  1. Заголовок - обозначает тип файла: GUI, CUI или DLL;
  2. Заголовок CLR - информация для превращение данного модуля в управляемый (расположение метаданных, точку входа и.т.д);
  3. Метаданные - 2 таблицы, описывающие типы данных и их члены;
  4. IL код - CLR компилирует его в машинный код в дальнейшем.
Зачем нужны метаданные? На них работает IntelliSinse, не нужна никакая дополнительная информация о коде, так как все хранится в в исполняемом файле, помогают сборщику мусора и сериализации.

Среда CLR работает со сборками. Сборка - это объединение исполняемых файлов в одну логическую сущность, описанную манифестом. Благодаря сборкам, работающим с управляемым кодом, нет необходимости в реестре, как в случает с неуправляемым кодом.
Сборка разбивает управляемые модули и ресурсные файлы.

Сборка представляет собой dll файл или приложение. В процессе разработки скорее всего будет использоваться язык высокого уровня, например C#, который не использует в полную мощь среду CLR. Для использования каких-то особенный функций можно писать часть приложения на ассемблере IL

Перед выполнением JIT компиляторы переводят в машинный код IL код. При этом CLR вызывает JIT компилятор только при первой компиляции типа. В дальнейшем это уже не потребуется, так как все будет загружено в память.

Разработка ORACLE PL/SQL - ASP MVC 3- JavaScript

Всем привет! 
Хотелось поделиться со всеми своими наработками веб-приложений. Я не являюсь гуру или даже близким к нему, но как-то получилось так, что я искал на чем же мне начать писать веб приложения, и вот труды моих поисков)

Первым, с чем я познакомился, был девэкспресс. Я обрадовался, и думал что вот оно, создание приложения как в веб формс (перетаскиваем формочки и никаких проблем), но сразу наткнулся на кучу проблем. Например, девэкспресс начинает жутко тормозить при работе с большими таблицами, и как-то непонято было как оно внутри работает. Плюс куча настроек, которые я вытаскивал из примеров и форумов, меня начали выбешивать, поэтому плюнов на все, я решил поискать что-то другое.

НО! Девэкспресс очень крутая штука (ввиду своей криворукости не смог высидеть прозрение), фактически можно использую минимум знаний css javascript и htlm - сварганить красивые формы, и главное, очень быстро! Плюс подключив, XPO можно отгородиться от DML (Select Insert Update Delete), а также заморочки с транзакциями и всякой лабудой.

Вообщем я никогда не любил ORM, как-то я люблю Oracle и все его фишки, и отказывать от них мне не хотелось, ну страшно мне смотреть на то, как что-то терзает базу данных непонятными запросами, еще и план непонятно какой. 
К чему я пришел в итоге?

ORM я решил писать свой, точнее его ORM назвать я думаю нельзя) Это повсеместно используемый подход.

Все манипуляции с БД я делал PL/SQL процедурами, точнее все запросы и DML я вынес в хранимки. Так, с первым уровнем решили. Дальше сервер приложений.


Сервер приложений.....Какой? Я выбрал IIS, так как очень удобна в стеке мелкософта реализована SSO. Пользователь ввел логин в виндоус и спокойно работает с приложением без дополнительных заморочек с авторизацией. Ну да, глуповат я для линуксов и апатчей. 
А может нужно было пойти J2EE путем? Oracel Java отличная связка, с учетом что это все теперь единое целое. 
Я попробовал: Servet, JSP , JSF , ADF. Пробовал на GlassFish и Weblogic, подключая при этом EJB и даже пробовал Hibernate. Java велика! Кучи фреймворков, кучи xml связок между разными фреймворками. Для больших решений, это было бы оправдано, но я работаю один, даже командной разработки толком нет никакой, поэтому я все выкинул. Кстати: Servet, JSP , JSF меня насторожили тем, что все технологии очень медленно развиваются и концепция последнего мне совсем не понравилась. 

Стек LAMP (Linux-Apache-MySQL-PHP ) не подошел по корпоративным принципам, да и используется он по большей части для создания сайтов.

Ну так вот IIS, какая Технология разработки? Web Forms? Нет! Опять от меня прячут все! Дайте код посмотреть!))
ASP MVC! Вот это красота) Паттерн MVC мне всегда нравился - все наглядно и полный контроль.

На чем писать клиентскую часть?
JS - фреймворки, все! не смогут обеспечить работу с большими таблицами (группировки, сортировки и.т.д) так как они тащут все исходные данные на клиент, и обрабатывают их средствами браузера. Как писать сами html - страницы? Хелперы? Опять получается некое скрытие html.

Вот оно: javascript, css, html5, jQuery, Twitter Bootstrap!

Что в итоге мне было нужно? Фреймворк, работающий с ораклом, он должен быть открыт на модификацию, и я хочу полный контроль происходящего. 
Пришлось писать свой. Которым я хочу поделиться.
Принцип его работы очень прост:
1) Пакет оракла содержит функции для удаления, обновления, вставки и извлечения данных.
2) На asp MVC есть класс и ORM класс, которые выполняют вызов функций Oracle. Контроллеры посылают JSON на клиент.
3) Клиент принимает JSON и перестраивает динамечески таблицу

Тут первая часть, делаем обычную таблицу

Разработка ORACLE PL/SQL - ASP MVC 3- JavaScript Часть 1. Создание простой таблицы

Небольшой обзор технологий я уже сделал в предыдущей статье, здесь я хотел бы показать как я реализовал свой подход:

Создание хранимых процедур
Справочник регионов.
Пакет:

create or replace package admin_REGION_V01 as

    function f_sel_REGION return tab_select_REGION pipelined;

    function f_upd_REGION(p_REGION_ID        in NUMBER,
                                                p_REGION_NAME in VARCHAR2) return varchar2;

    function f_ins_REGION( p_REGION_NAME in VARCHAR2) return varchar2;

    function f_del_REGION(p_REGION_ID in NUMBER) return varchar2;

end admin_REGION_V01;


Тело пакета:

create or replace package body admin_REGION_V01 as

    function f_sel_REGION return tab_select_REGION  pipelined
    as
        l_t_select_REGION t_select_REGION;
    begin
       l_t_select_REGION:= t_select_REGION(0,'');
       for C in (select
                    REGION_ID,REGION_NAME
                from REGION
       )
       loop
         l_t_select_REGION.REGION_ID:= C.REGION_ID;
         l_t_select_REGION.REGION_NAME:= C.REGION_NAME;

       pipe row (l_t_select_REGION);

       end loop;

    return;
    end f_sel_REGION;

    function f_upd_REGION( p_REGION_ID   in NUMBER,
                           p_REGION_NAME in VARCHAR2) return varchar2
    as
        pragma autonomous_transaction;
        my_errm VARCHAR2(32000);
    begin
       update REGION
       set  REGION_NAME = p_REGION_NAME
       where REGION_ID= p_REGION_ID;

      commit;
     return 'REGION:' || p_REGION_NAME ||' was success updated';
    exception when others then
              my_errm := SQLERRM;
              rollback;
              return my_errm;
    end f_upd_REGION;

    function f_ins_REGION( p_REGION_NAME   in VARCHAR2) return varchar2
    as
        pragma autonomous_transaction;
        my_errm VARCHAR2(32000);
    begin
       insert into REGION
       (
         REGION_ID,
         REGION_NAME
       )
       values (
         seq_groups_id.nextval,
         p_REGION_NAME);
      commit;
     return 'REGION:' || p_REGION_NAME|| 'was success inserted';
    exception when others then
              my_errm := SQLERRM;
              rollback;
              return my_errm;
    end f_ins_REGION;

    function f_del_REGION(p_REGION_ID   in NUMBER) return varchar2
    as
       pragma autonomous_transaction;
       my_errm VARCHAR2(32000);
    begin
       delete from REGION
       where REGION_ID =p_REGION_ID;
       commit;
     return 'REGION: '|| p_REGION_ID||' was success deleted';
    exception when others then
        my_errm := SQLERRM;
        rollback;
        return my_errm;
    end f_del_REGION;
    
end admin_REGION_V01;


Тут собственно я обернул все необходимые DML для работы приложения с таблицей.

Дальше в ASP MVC делаем класс, фактически это все колонки Вашей таблицы:


namespace TEST.Models.OracleORM.classes
{
public class Region
{
public int RegionRegionId { set; get; }
public string RegionRegionName { set; get; }

public Region() { }
}
}


Далее ORM класс, который будет вызывать хранимые процедуры:


using System;
using System.Collections.Generic;
using COMMON.Oracle;
using Erequest3AdminTool.Models.OracleORM.classes;

namespace Erequest3AdminTool.Models.OracleORM
{
    public class RegionIUDS
    {
        private static String RegionSelect = @" select    region_id           F01
                                                                                            ,region_name     F02                                                        
                                               from table(admin_region_v01.f_sel_region())";

        private static String RegionUpdate = @"select admin_region_v01.f_upd_region(  p_REGION_ID   =>  &p_REGION_ID
                                                                                     ,p_REGION_NAME => '&p_REGION_NAME') results from dual";

        private static String RegionInsert = @"select admin_region_v01.f_ins_region( p_REGION_NAME => '&p_REGION_NAME') results from dual";

        private static String RegionDelete = @"select admin_region_v01.f_del_region(p_REGION_ID   =>&p_REGION_ID ) results from dual";

       
        public static List<Region> SelectRegion()
        {
            List<Region> result = new List<Region>();
            try
            {
                foreach (OracleField row in OracleLib.setExecuteSelect(RegionSelect))
                {
                    result.Add(new Region()
                    {
                        RegionRegionId = Convert.ToInt32(row.F01),
                        RegionRegionName = row.F02
                    });
                }
            }
            catch
            {
                throw;
            }

            return result;
        }

      public static string UpdateRegion(Region Region)
        {
            string result = "";
            try
            {
                String l_sql = RegionUpdate;

                l_sql = l_sql.Replace("&p_REGION_ID", Convert.ToString(Region.RegionRegionId));
                l_sql = l_sql.Replace("&p_REGION_NAME", Region.RegionRegionName);
              

                result = OracleLib.setExecuteIUD(l_sql);
            }
            catch
            {
                throw;
            }
            return result;
        }

      
        public static string InsertRegion(Region Region)
        {
            string result = "";
            try
            {
                String l_sql = RegionInsert;
               
                l_sql = l_sql.Replace("&p_REGION_NAME", Region.RegionRegionName);

                result = OracleLib.setExecuteIUD(l_sql);
            }
            catch
            {
                throw;
            }
            return result;
        }

       
        public static string DeleteRegion(int RegionRegionId)
        {
            string result = "";
            try
            {
                String l_sql = RegionDelete;

                l_sql = l_sql.Replace("&p_REGION_ID", Convert.ToString(RegionRegionId));

                result = OracleLib.setExecuteIUD(l_sql);
            }
            catch
            {
                throw;
            }
            return result;
        }
    }
}

Смысл я думаю понятен, просто перезаписываем переменные какими-то значениями, которые передаются из контроллера.

Далее контроллер:


namespace Erequest3AdminTool.Controllers
{
    public class RegionController : Controller
    {
        /// <summary>
        /// Полная страница для отображения
        /// </summary>       
        public ActionResult RegionShowPage()
        {
            return View("RegionTable");
        }

        /// <summary>
        /// Передает список всех пользователей через JSON
        /// </summary>       
        public ActionResult RegionSelect()
        {          
            return Json(RegionIUDS.SelectRegion(), JsonRequestBehavior.AllowGet);
        }

        /// <summary>
        /// Обновить данные о Region
        /// </summary>
        /// <param name="Region">JSON, содержит информацию для обновления</param>
        [HttpPost]
        public ActionResult RegionUpdate(Region Region)
        {
            try
            {
                if (ModelState.IsValid)
                {
                    string results = RegionIUDS.UpdateRegion(Region);

                    if (results.Contains("ORA"))
                    {
                        return PartialView("~/Views/Shared/error.cshtml", results);
                    }
                    else
                    {
                        return PartialView("~/Views/Shared/done.cshtml", results);
                    }
                }
                else
                {
                    return PartialView("~/Views/Shared/error.cshtml", "RegionUpdate invalid Model");
                }
            }
            catch (Exception e)
            {
                return View("~/Views/Shared/error.cshtml", e.Message);
            }
        }

        /// <summary>
        /// Добавление данных в Region
        /// </summary>
        /// <param name="Region">JSON, содержит информацию для обновления</param>
        [HttpPost]
        public ActionResult RegionInsert(Region Region)
        {
            try
            {
                if (ModelState.IsValid)
                {
                    string results = RegionIUDS.InsertRegion(Region);

                    if (results.Contains("ORA"))
                    {
                        return PartialView("~/Views/Shared/error.cshtml", results);
                    }
                    else
                    {
                        return PartialView("~/Views/Shared/done.cshtml", results);
                    }
                }
                else
                {
                    return PartialView("~/Views/Shared/error.cshtml", "RegionInsert invalid Model");
                }
            }
            catch (Exception e)
            {
                return View("~/Views/Shared/error.cshtml", e.Message);
            }
        }

        /// <summary>
        /// Удаление данных в Region
        /// </summary>
        /// <param name="Region">JSON, содержит информацию для удаления</param>
        [HttpPost]
        public ActionResult RegionDelete(string RegionRegionId)
        {
            try
            {
                if (ModelState.IsValid)
                {
                    string results = RegionIUDS.DeleteRegion(Convert.ToInt32(RegionRegionId));

                    if (results.Contains("ORA"))
                    {
                        return PartialView("~/Views/Shared/error.cshtml", results);
                    }
                    else
                    {
                        return PartialView("~/Views/Shared/done.cshtml", results);
                    }
                }
                else
                {
                    return PartialView("~/Views/Shared/error.cshtml", "RegionDelete invalid Model");
                }
            }
            catch (Exception e)
            {
                return View("~/Views/Shared/error.cshtml", e.Message);
            }
        }

    }

}

Фактически контроллеры принимают JSON и вызывают методы класса ORM.
И наконец View:



<!--load js-->

<script src="@Url.Content("~/Content/JavaScript/JsORM/Region/js/RegionTable.js")"></script>



<div class="span4">
   <h4>Regions</h4>
   <div style="overflow-x: auto; width: 100%" id="allRegions"></div>
</div>


Тут все происходит в RegionTable.js:

var tableRegionDescription = {
TableID: 'Region'
, ContentDiv: '#allRegions'
, Columns: [{ ColumnName: "Region Name", ColumnID: "RegionRegionName", IsSort: 1, ColumnType: 'text', IsVisible: 'true', IsPK: 'false' }
,{ ColumnName: "Id", ColumnID: "RegionRegionId", IsSort: 0, ColumnType: 'text', IsVisible: 'false', IsPK: 'true' }]
, DeleteController: '/Region/RegionDelete'
, InsertController: '/Region/RegionInsert'
, UpdateController: '/Region/RegionUpdate'
, SelectController: '/Region/RegionSelect'
, tableData: []
};

$(document).ready(function () {

//создаем заголовок для таблицы и саму таблицу без данных
$(tableRegionDescription.ContentDiv).createTableHead(tableRegionDescription);

//заполняем таблицу данными
$().createTable(tableRegionDescription);

});


И вот что мы получаем:

region

По поводу параметров:

TableID: - идентификатор таблицы, которая будет добавлена
, ContentDiv: - ID DIV, куда добавлять таблицу
, Columns: массив колонок таблицы
ColumnName - имя отображаемой колонки
ColumnID - идентификатор колонки
IsSort - включить сортировку
ColumnType - тип колонки
IsVisible - отображать в таблице или нет
IsPK - колонка, которая является первичным ключом, необходимо будет при удаление данных из таблицы
, SelectController: - контроллер, которые будет получать данные
, tableData: [] - массив, содержащий данные, которые будут загружены из SelectController