среда, 29 июня 2011 г.

Разработка бизнес приложения на silverlight –Часть 2 (создание WCF Ria Services)

    В этой статье, мы продолжаем создавать наше бизнес приложение для отображения базы зданий. И сейчас нам необходимо добавить службу домена в проект среднего уровня. Служба домена предоставляет клиентскому проекту сущности данных и операции из серверного проекта. В службу домена можно добавить бизнес-логику для управления взаимодействием клиента с данными. Как создать службу домена в проект?
    1. Щелкните правой кнопкой мыши серверный проект, выберите Добавить, а затем Новый элемент.
    2. В списке категорий выберите Интернет, а затем выберите шаблон Класс службы домена.
    3. Назовите класс BuildingDomainService.cs 
    1. Нажмите кнопку Добавить.
    Откроется диалоговое окно Добавление нового класса службы домена.
    1. Убедитесь, что установлен флажок Разрешить клиентский доступ.
    2. Выберите сущность Building и Flor, а затем установите для нее флажок Разрешить изменение.
    1. Нажмите кнопку ОК.
    Класс BuildingDomainService будет создан в новом файле BuildingDomainService.cs.
    1. Откройте этот файл. Обратите внимание, что файл обладает следующими характеристиками.
    ·         Класс BuildingDomainService происходит от класса LinqToEntitiesDomainService, который является абстрактным базовым классом из платформы Службы RIA . Этот базовый класс был использован автоматически, поскольку служба домена предоставляет класс данных ADO.NET Entity.
    ·         Универсальный базовый класс привязан к классу сущности, созданному на предыдущих шагах с помощью BuildingEntities типа ObjectContext в его универсальном параметре.
    ·         Класс BuildingDomainService помечен атрибутом EnableClientAccessAttribute, указывающим, что он является видимым для клиентского уровня.
    ·         Создается метод запроса с именем GetBuildings. Этот метод возвращает все элементы без фильтрации и сортировки.
      • Были созданы методы для вставки, обновления и удаления зданий и этажей из записей.
    Рассмотрим подробнее, что у нас получилось. Основное на что следует обратить внимание, это MetadataAttribute. Я использовала основные из них, давайте выясним что они значат.

    1)      Аттрибут Display - Предоставляет атрибут общего назначения, позволяющий указывать локализуемые строки для типов и членов разделяемых классов сущностей. Вот его свойства:

    Имя
    Описание
    Получает или задает значение, указывающее, нужно ли для отображения этого поля автоматически создавать пользовательский интерфейс.
    Added exception.
    Получает или задает значение, которое используется для отображения описания пользовательского интерфейса.
    Получает или задает значение, используемое для группировки полей в пользовательском интерфейсе.
    Получает или задает значение, которое используется для отображения в элементе пользовательского интерфейса.
    Получает или задает порядковый вес столбца.
    Получает или задает значение, которое будет использоваться для задания подсказки в элементе пользовательского интерфейса.
    Получает или задает тип, содержащий ресурсы для свойств ShortNameNamePrompt и Description.
    Получает или задает значение, используемое в качестве метки столбца сетки.
    При реализации в производном классе возвращает уникальный идентификатор для этого Attribute. (Унаследовано от Attribute.)
    2)      Аттрибут Required - Указывает, что требуется значение поля данных. Вот его свойства.
    Имя
    Описание
    Получает или задает значение, указывающее на то, разрешена ли пустая строка.
    Получает или задает сообщение об ошибке, которое необходимо связать с проверяющим элементом управления на случай сбоя во время проверки.(Унаследовано от ValidationAttribute.)
    Получает или задает имя ресурса сообщений об ошибках, используемого для поиска значения свойства ErrorMessageResourceType в случае сбоя при проверке. (Унаследовано от ValidationAttribute.)
    Получает или задает тип ресурса, используемого для поиска сообщения об ошибке в случае сбоя проверки. (Унаследовано от ValidationAttribute.)
    Получает локализованное сообщение об ошибке проверки. (Унаследовано от ValidationAttribute.)
    При реализации в производном классе возвращает уникальный идентификатор для этого Attribute. (Унаследовано от Attribute.)

    Остальные атрибуты, если вам понадобятся, вы без труда найдёте в msdn по этой ссылке http://msdn.microsoft.com/ru-ru/library/cc490428.aspx

    namespace BuildingApp.Web.DataAccess
    {
        using System;
        using System.Collections.Generic;
        using System.ComponentModel;
        using System.ComponentModel.DataAnnotations;
        using System.Data.Objects.DataClasses;
        using System.Linq;
        using System.ServiceModel.DomainServices.Hosting;
        using System.ServiceModel.DomainServices.Server;


        // The MetadataTypeAttribute identifies BuildingMetadata as the class
        // that carries additional metadata for the Building class.
        [MetadataTypeAttribute(typeof(Building.BuildingMetadata))]
        public partial class Building
        {

            // This class allows you to attach custom attributes to properties
            // of the Building class.
            //
            // For example, the following marks the Xyz property as a
            // required property and specifies the format for valid values:
            //    [Required]
            //    [RegularExpression("[A-Z][A-Za-z0-9]*")]
            //    [StringLength(32)]
            //    public string Xyz { get; set; }
            internal sealed class BuildingMetadata
            {

                // Metadata classes are not meant to be instantiated.
                private BuildingMetadata()
                {
                }
                [Required]
                [StringLength(500)]
                [Display(Order = 1, Name = "Адрес")]
                public string Address { get; set; }

                [Display(Order = 3, Name = "Дата постройки")]
                public Nullable<DateTime> CreationDate { get; set; }
               
                [Display(AutoGenerateField = false)]
                public EntityCollection<Floor> Floor { get; set; }

                [Display(Order = 2, Name = "Этажность")]
                public Nullable<int> FloorCount { get; set; }
               
                [Display(AutoGenerateField = false)]
                public int ID { get; set; }
               
                [Display(Order = 7, Name = "Макс.арендная ставка (руб.)")]
                public Nullable<int> MaxRentalRate { get; set; }

                [Display(Order = 6, Name = "Мин.арендная ставка (руб.)")]
                public Nullable<int> MinRentalRate { get; set; }
               
                [Required]
                [StringLength(200)]
                [Display(Order = 0, Name = "Название")]
                public string Name { get; set; }
               
                [Display(Order = 5, Name = "Общее кол-во помещений")]
                public Nullable<int> Room { get; set; }

                [Display(Order = 8, Name = "Кол-во арендаторов")]
                public Nullable<int> TenantsCount { get; set; }

                [Display(Order = 4, Name = "Общая площадь (кв.м)")]
                public Nullable<int> TotalArea { get; set; }
            }
        }

        // The MetadataTypeAttribute identifies FloorMetadata as the class
        // that carries additional metadata for the Floor class.
        [MetadataTypeAttribute(typeof(Floor.FloorMetadata))]
        public partial class Floor
        {

            // This class allows you to attach custom attributes to properties
            // of the Floor class.
            //
            // For example, the following marks the Xyz property as a
            // required property and specifies the format for valid values:
            //    [Required]
            //    [RegularExpression("[A-Z][A-Za-z0-9]*")]
            //    [StringLength(32)]
            //    public string Xyz { get; set; }
            internal sealed class FloorMetadata
            {

                // Metadata classes are not meant to be instantiated.
                private FloorMetadata()
                {
                }
                [Display(Order = 1, Name = "Общая площадь (кв.м)")]
                public Nullable<int> Area { get; set; }
              
                [Display(AutoGenerateField = false)]
                public Building Building { get; set; }
               
                [Display(AutoGenerateField = false)]
                public int BuildingID { get; set; }

                [Required]
                [Editable(false, AllowInitialValue=true)]
                [Display(Order = 0, Name = "Номер этажа")]
                public int Number { get; set; }

                [Display(Order = 2, Name = "Кол-во арендаторов")]
                public Nullable<int> TenantsCount { get; set; }
            }
        }
    }

    Теперь рассмотрим DomainService. Наш класс BuildingDomainService содержит основные методы для работы с данными, такие как получение, вставка, обновление и удаление данных. Если нам необходима изменить их логику или добавить свои методы работы с данными, мы может это сделать в данном классе.

    namespace BuildingApp.Web.DomainService
    {
        using System;
        using System.Collections.Generic;
        using System.ComponentModel;
        using System.ComponentModel.DataAnnotations;
        using System.Data;
        using System.Linq;
        using System.ServiceModel.DomainServices.EntityFramework;
        using System.ServiceModel.DomainServices.Hosting;
        using System.ServiceModel.DomainServices.Server;
        using BuildingApp.Web.DataAccess;


        [EnableClientAccess()]
        public class BuildingDomainService : LinqToEntitiesDomainService<BuildingDBEntities>
        {

            // TODO:
            // Consider constraining the results of your query method.  If you need additional input you can
            // add parameters to this method or create additional query methods with different names.
            // To support paging you will need to add ordering to the 'Building' query.
            public IQueryable<Building> GetBuilding()
            {
                return this.ObjectContext.Building;
            }

            public void InsertBuilding(Building building)
            {
                if ((building.EntityState != EntityState.Detached))
                {
                    this.ObjectContext.ObjectStateManager.ChangeObjectState(building, EntityState.Added);
                }
                else
                {
                    this.ObjectContext.Building.AddObject(building);
                }
            }

            public void UpdateBuilding(Building currentBuilding)
            {
                this.ObjectContext.Building.AttachAsModified(currentBuilding, this.ChangeSet.GetOriginal(currentBuilding));
            }

            public void DeleteBuilding(Building building)
            {
                if ((building.EntityState == EntityState.Detached))
                {
                    this.ObjectContext.Building.Attach(building);
                }

                foreach (Floor floor in this.ObjectContext.Floor.Where(p=>p.BuildingID == building.ID))
                {
                    this.ObjectContext.Floor.DeleteObject(floor);
                }

                this.ObjectContext.Building.DeleteObject(building);
            }

            // TODO:
            // Consider constraining the results of your query method.  If you need additional input you can
            // add parameters to this method or create additional query methods with different names.
            // To support paging you will need to add ordering to the 'Floor' query.
            public IQueryable<Floor> GetFloor()
            {
                return this.ObjectContext.Floor;
            }

            public IQueryable<Floor> GetFloorsByBuilding(int bID)
            {
                return this.ObjectContext.Floor.Where(p => p.BuildingID == bID);
            }

            public void InsertFloor(Floor floor)
            {
                if ((floor.EntityState != EntityState.Detached))
                {
                    this.ObjectContext.ObjectStateManager.ChangeObjectState(floor, EntityState.Added);
                }
                else
                {
                    this.ObjectContext.Floor.AddObject(floor);
                    //if (this.ObjectContext.Floor.Where(p => p.Number == floor.Number).Count() > 0)
                    //{
                    //    this.ObjectContext.Floor.AddObject(floor);
                    //}
                }
            }

            public void UpdateFloor(Floor currentFloor)
            {
                this.ObjectContext.Floor.AttachAsModified(currentFloor, this.ChangeSet.GetOriginal(currentFloor));
            }

            public void DeleteFloor(Floor floor)
            {
                if ((floor.EntityState == EntityState.Detached))
                {
                    this.ObjectContext.Floor.Attach(floor);
                }
                this.ObjectContext.Floor.DeleteObject(floor);
            }
        }
    }

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

Комментариев нет:

Отправить комментарий