Правильный способ создания доменных моделей и моделей представления в микросервисах - PullRequest
0 голосов
/ 14 декабря 2018

Я пытаюсь создать микросервис и пытаюсь убедиться, что я следую рекомендациям / шаблонам при проектировании моих объектов.

Я планирую разделить свои объекты, чтобы был один для возврата (запрашиваяиспользуя dapper) для клиентов (код класса ниже) и тот, который фактически вносит изменения состояния (код не в этом вопросе), который будет фиксировать изменения в db

У меня есть сущность CalendarEvents в dbи у меня есть viewmodel для этого, называемый CalendarEvent, и он имеет базовые свойства для каждого из полей сущности для отображения, и у меня есть куча других свойств для CalendarEvent, которые являются совокупностями полей сущности.

Вопросы:

  1. Как правильно заполнить этот объект CalendarEvent (viewmodel), если все свойства будут переданы через конструктор при создании из объекта, который читается из БД илиесть лучший способ сделать это.

  2. Должен ли я взять в _dateformat или есть более elegant way (это исходит из файла конфигурации)

Ниже приведен мой класс для CalendarEntity (класс, который будет использоваться в качестве viewmodel)

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

public class CalendarEvent
{
    private readonly string _dateFormat;
    public CalendarEvent(string dateFormat)
    {
        _dateFormat = dateFormat;
    }

    public int EventId { get; set; }

    public string Title { get; set; }

    public DateTime? StartDateTimeUtc { get; set; }

    public DateTime? EndDateTimeUtc { get; set; }

    public string Summary { get; set; }

    public bool IsApproved { get; set; }

    public string TimeZoneId { get; set; }

    public bool IsDeleted { get; set; }

    public int ViewCount { get; set; }

    public DateTime CreatedDateUtc { get; set; }

    public DateTime? FeaturedStartDateUtc { get; set; }

    public DateTime? FeaturedEndDateUtc { get; set; }

    public string ContactEmailAddress { get; set; }

    public EventDateType DateType { get; set; }

    public int? Year { get; set; }

    public int? Period { get; set; }


    public EventCategory Category { get; set; }

    public string UrlFriendlyTitle => Helper.UrlFriendly(Title);

    public DateTime? EndDateTimeLocal { get; set; }

    public DateTime? StartDateTimeLocal { get; set; }

    public string FullEventDateString
    {
        get
        {
            string dateString;
            switch (DateType)
            {
                case EventDateType.Month:
                    {
                        var monthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(Period.Value);
                        dateString = $"{monthName} {Year}";
                        break;

                    }
                case EventDateType.Quarter:
                    {
                        dateString = $"{Period}{Helper.GetNumberOrdinalSuffix(Period.Value)} Quarter {Year}";
                        break;
                    }
                case EventDateType.Specific:
                    {
                        if (StartDateTimeLocal.HasValue && EndDateTimeLocal.HasValue)
                        {
                            if (StartDateTimeLocal.Value.Date == EndDateTimeLocal.Value.Date)
                            {
                                if (StartDateTimeLocal.Value.Date == EndDateTimeLocal.Value.Date
                                    && StartDateTimeLocal.Value.Hour == 0 && StartDateTimeLocal.Value.Minute == 0 &&
                                    StartDateTimeLocal.Value.Second == 0 && EndDateTimeLocal.Value.Hour == 23)
                                {
                                    dateString = StartDateTimeLocal.Value.ToString(_dateFormat);
                                }
                                else
                                {

                                    var eventDateTime =
                                        $"{StartDateTimeLocal.Value.ToString(_dateFormat)} {StartDateTimeLocal.Value.ToShortTimeString()} - {EndDateTimeLocal.Value.ToShortTimeString()}";
                                    dateString = eventDateTime;
                                }
                            }
                            else
                            {
                                var eventDateTime =
                                    $"{StartDateTimeLocal.Value.ToString(_dateFormat)} - {EndDateTimeLocal.Value.ToString(_dateFormat)}";

                                dateString = eventDateTime;
                            }


                            break;

                        }
                        //TODO: fix this
                        throw new NotImplementedException();

                    }
                default:
                    throw new ArgumentOutOfRangeException();
            }


            return dateString;
        }
    }

    public EventStatuses Status
    {
        get
        {
            if (IsDeleted)
            {
                return EventStatuses.Deleted;
            }
            if (StartDateTimeUtc > DateTime.UtcNow)
            {
                return EventStatuses.NotStarted;
            }
            if (StartDateTimeUtc <= DateTime.UtcNow && EndDateTimeUtc > DateTime.UtcNow)
            {
                return EventStatuses.InProgress;
            }
            return EventStatuses.Completed;
        }
    }

    public string UrlFriendlyTitleForDisplay
    {
        get
        {
            var textInfo = new CultureInfo("en-US", false).TextInfo;
            return textInfo.ToTitleCase(UrlFriendlyTitle.ToLower().Replace("-", " "));

        }
    }

    private void GenerateLocalTimes()
    {

        if (DateType == EventDateType.Specific && StartDateTimeUtc.HasValue && EndDateTimeUtc.HasValue)
        {

            var tz = TimeZoneInfo.FindSystemTimeZoneById(TimeZoneId);

             //TODO: make sure ticks is zero in this case, this use to be totalSeconds comparison
            if (tz.BaseUtcOffset.Ticks == 0)
            {
                EndDateTimeLocal = EndDateTimeUtc;
                StartDateTimeLocal = StartDateTimeUtc;
            }
            else
            {
                EndDateTimeLocal = TimeZoneInfo.ConvertTimeFromUtc(EndDateTimeUtc.Value, tz);
                StartDateTimeLocal = TimeZoneInfo.ConvertTimeFromUtc(StartDateTimeUtc.Value, tz);
            }
        }
        else
        {

            //TODO: fix this
            throw new NotImplementedException();
        }
    }

    public string GoogleCalendarLink
    {
        get
        {
            if (DateType == EventDateType.Specific && StartDateTimeUtc.HasValue && EndDateTimeUtc.HasValue)
            {
                var text = string.Empty;
                if (!string.IsNullOrEmpty(Title))
                {
                    text = Uri.EscapeUriString(Title);
                }

                var startDate = StartDateTimeUtc.Value.ToString("yyyyMMddTHHmmssZ");
                var endDate = EndDateTimeUtc.Value.ToString("yyyyMMddTHHmmssZ");
                var details = string.Empty;
                if (!string.IsNullOrEmpty(Summary))
                {
                    details = Uri.EscapeUriString(Summary);
                }

                return
                    $"http://www.google.com/calendar/event?action=TEMPLATE&text={text}&dates={startDate}/{endDate}&details={details}&location=";
            }

            //TODO: fix this
            throw new NotImplementedException();

        }
    }
}

1 Ответ

0 голосов
/ 14 декабря 2018

Я предполагаю, что вы используете Web Api, но те же принципы применимы к приложению MVC.У меня обычно есть слой картографирования, который берет объект домена и отображает его на модель представления или dto.Таким образом, вы можете повторно использовать маппер в любое время, когда захотите вернуть ту же модель представления.Поэтому, если вы вносите изменения в модель представления, все это находится в одном месте.

См. Код ниже, чтобы ответить на вопрос 1.

Вопрос 2: Почему ваш миросервис заботится о том, какую дату хочет получить клиент.Если вы отправляете обратно дату utc, то, если клиент хочет, чтобы она была в формате, то его можно отформатировать.

//Fake view model
public class CalendarEventViewModel
{
    public int EventId { get; set; }

    public string Title { get; set; }

    public DateTime? StartDateTimeUtc { get; set; }

    public DateTime? EndDateTimeUtc { get; set; }

    public string Summary { get; set; }

    public bool IsApproved { get; set; }

    public string TimeZoneId { get; set; }
}


public interface IMapper<in TIn, out TOut>
{
        TOut Map(TIn model);
}

public class CalendarEventViewModelMapper : IMapper<CalendarEvent, CalendarEventViewModel>
{
    public CalendarEventViewModel Map(CalendarEvent model)
    {
        return new CalendarEventViewModel
        {
            EndDateTimeUtc = model.EndDateTimeUtc,
            EventId = model.EventId,
            IsApproved = model.IsApproved,
            StartDateTimeUtc = model.StartDateTimeUtc,
            Summary = model.Summary,
            TimeZoneId = model.TimeZoneId,
            Title = model.Title
        };
    }
}

[Route("api/Values")]
public class ValuesController 
{ 
       public ValuesController( IMapper<CalendarEvent, CalendarEventViewModel> calendarMapper)
       {
           _calendarMapper = calendarMapper;
       }

        // GET api/values/5
        [HttpGet("{id}")]
        public IActionResult Get(int id)
        {

            var calendarEvent = GetMyCalendarEventFromDB(id);

            return this.Ok(_calendarMapper.Map(calendarEvent));
        }

        private CalendarEvent GetMyCalendarEventFromDB(int id)
        {
            return new CalendarEvent("yyyy-dd-MM")
            {
                EndDateTimeUtc = DateTime.UtcNow.AddHours(3),
                EventId = id,
                IsApproved = true,
                StartDateTimeUtc = DateTime.UtcNow.AddHours(2),
                Summary = "My magical Event",
                TimeZoneId = "UTC",
                Title = "Magical Event"
            };
        }
    }
}

Folder structure

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...