4
\$\begingroup\$

This is my first experience of designing classes with inheritance. I would like to get feedback on the interaction between the presented classes. It is unlikely that this code will seem complicated. But if you need a description of it, please specify in the comments.

There are several classes that describe the model.

  • ToolStripUI Сontains properties for configuring the UI.
  • SearchArgs Inherited from EventArgs. Required to pass data to the search method.
  • PagedModelBase<T> It is necessary to implement the output of data on the page.
  • SearchModel<T> Extension for PagedModelBase in the search part.
  • TableModel<T> Extension for PagedModelBase in normal mode. Forces the Find() and Delete() methods to be implemented.

They are used to create two models: Contract and Worker. They inherit TableModel. And each has a inner class SearchModel that inherits SearchModel<T>.

A change in the PagedModelBase<T> properties causes a change in ToolStripUI. Thus, ToolStripUI always contains relevant data for UI.

The following code shows how the Contract model methods are used.

private void OnButtonToolStripClick(object sender, TSButton btn)
{
    switch (form.CurrentTable)
    {
        case TableName.CONTRACT:
            if (model.GetContractModel.GetSearch.IsSearch)
            {
                SearchTableContract(btn);
            }
            else
            {
                TableContract(btn);
            }
            break;

        case TableName.WORKER:
            if (model.GetWorkerModel.GetSearch.IsSearch)
            {
                SearchTableWorker(btn);
            }
            else
            {
                TableWorker(btn);
            }
            break;
    }
}

private void SearchTableContract(TSButton btn)
{
    List<ContractTableRow> list;
    ToolStripUI ui;

    switch (btn)
    {
        case TSButton.SEARCH:
            list = model.GetContractModel.Find(form.GetSearchItem());
            break;
        case TSButton.RESET:
            list = model.GetContractModel.ReloadPage();
            break;
        case TSButton.FIRST:
            list = model.GetContractModel.GetSearch.FirstPage();
            break;
        case TSButton.LAST:
            list = model.GetContractModel.GetSearch.LastPage();
            break;
        case TSButton.NEXT:
            list = model.GetContractModel.GetSearch.NextPage();
            break;
        case TSButton.PREVIOUS:
            list = model.GetContractModel.GetSearch.PreviousPage();
            break;
        default:
            list = null;
            break;
    }

    if (btn == TSButton.RESET)
    {
        ui = model.GetContractModel;
    }
    else
    {
        ui = model.GetContractModel.GetSearch;
    }

    if (list.Count > 0)
    {
        contractUC.FillPage(list);
        form.SetToolStipUI(ui);
    }
    else
    {
        ShowMessage.Information("Не найдено");
    }

}


private void TableContract(TSButton btn)
{
    List<ContractTableRow> list;
    ToolStripUI ui;

    switch (btn)
    {
        case TSButton.SEARCH:
            list = model.GetContractModel.Find(form.GetSearchItem());
            break;
        case TSButton.RESET:
            list = model.GetContractModel.ReloadPage();
            break;
        case TSButton.FIRST:
            list = model.GetContractModel.FirstPage();
            break;
        case TSButton.LAST:
            list = model.GetContractModel.LastPage();
            break;
        case TSButton.NEXT:
            list = model.GetContractModel.NextPage();
            break;
        case TSButton.PREVIOUS:
            list = model.GetContractModel.PreviousPage();
            break;
        default:
            list = null;
            break;
    }

    if (btn == TSButton.SEARCH)
    {
        ui = model.GetContractModel.GetSearch;
    }
    else
    {
        ui = model.GetContractModel;
    }

    contractUC.FillPage(list);
    form.SetToolStipUI(ui);
}

And the full code of all described classes. Perhaps more convenient to watch via GitHub.

public ContractModel GetContractModel { get; private set; }
public WorkerModel GetWorkerModel { get; private set; }
public MainModel()
{
    GetContractModel = new ContractModel();
    GetWorkerModel = new WorkerModel();
}

public class ContractModel : TableModel<ContractTableRow>
    {
        internal SearchModel GetSearch { get; set; }

        public ContractModel()
        {
            Size = Properties.Settings.Default.TableContractSize;
            GetSearch = new SearchModel();
        }

        internal override bool Delete(int id)
        {
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();

            bool result = true;

            try
            {
                using (ModelContext model = new ModelContext())
                {
                    Contracts c = model.Contracts.Single(x => x.Id == id);
                    model.Remove(c);
                    model.SaveChanges();
                }
                Count--;
            }
            catch (Exception ex)
            {
                result = false;
                ShowMessage.Error(string.Format(
                    "Во время удаления договора из базы данных произошла ошибка. ID договора: {0}\n\n{1} {2}",
                    id, ex.Message, ex.InnerException.Message), "Исключение - MainModel.DeleteContract");
            }

            stopwatch.Stop();
            logger.Debug("DeleteContract(): {0}", stopwatch.Elapsed);
            return result;
        }
        internal override List<ContractTableRow> LoadPage()
        {
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();

            List<ContractTableRow> source = null;
            try
            {
                using (ModelContext model = new ModelContext())
                {

                    Count = model.Contracts.Count();

                    IEnumerable<ContractTableRow> rows = model.Contracts
                        .OrderByDescending(r => r.Id)
                        .Skip(Page * Size)
                        .Take(Size)
                        .Select(c => new ContractTableRow
                        {
                            IdContract = c.Id,
                            Num = c.Num,
                            DateConclusion = c.DateConclusion.ToLongDateString(),
                            DateStartWork = c.DateStartWork.ToLongDateString(),
                            DateEndWork = c.DateEndWork.ToLongDateString(),
                            Salary = c.Salary,

                            Worker = new Item { Id = c.Worker, Value = c.WorkerNavigation.FullName },
                            KindWork = c.ListKindWorks.Select(y => new ItemLong { Id = y.IdKindWork, Title = y.IdKindWorkNavigation.Title, Short = y.IdKindWorkNavigation.Short }),
                            Subject = c.ListSubjects.Select(y => new ItemLong { Id = y.IdSubject, Title = y.IdSubjectNavigation.Title, Short = y.IdSubjectNavigation.Short })
                        });

                    source = rows.ToList();
                }

            }
            catch (Exception ex)
            {
                source = null;
                ShowMessage.Error(string.Format(
                    "Во время загрузки страницы с договорами произошла ошибка. Номер страницы: {0} (отсчет от {1})\n\n{2} {3}",
                    Page, MinPage, ex.Message, ex.InnerException.Message), "Исключение - MainModel.LoadPage");
            }

            stopwatch.Stop();
            logger.Debug("Load page: {0}", stopwatch.Elapsed);

            return source;
        }
        internal override List<ContractTableRow> Find(SearchArgs e)
        {
            return GetSearch.FirstPage(e);
        }
        internal override List<ContractTableRow> ReloadPage()
        {
            GetSearch.IsSearch = false;
            return base.ReloadPage();
        }

        internal class SearchModel : SearchModel<ContractTableRow>
        {
            public SearchModel()
            {
                Size = Properties.Settings.Default.TableSearchSize;
                ListTypeSearch = new List<ItemSearch>
                {
                    new ItemSearch { Value = "Num", Display = "Номер" },
                    new ItemSearch { Value = "DateConclusion", Display = "Заключен" },
                    new ItemSearch { Value = "Worker", Display = "Работник [ФИО]" },
                    new ItemSearch { Value = "IdWorker", Display = "Работник [ID]"},
                    new ItemSearch { Value = "KindWork", Display = "Вид работы" },
                    new ItemSearch { Value = "Subject", Display = "Объект" },
                    new ItemSearch { Value = "DateStartWork", Display = "Начало" },
                    new ItemSearch { Value = "DateEndWork", Display = "Окончание" },
                    new ItemSearch { Value = "Salary", Display = "Зарплата" }
                };

                GetItemIdWorker = ListTypeSearch[3];
            }

            internal override List<ContractTableRow> LoadPage()
            {
                Stopwatch stopwatch = new Stopwatch();
                stopwatch.Start();

                string pattern = GetPattern(GetArgs.IsExactMatch, GetArgs.Keyword);
                List<ContractTableRow> list = null;

                try
                {
                    using (var model = new ModelContext())
                    {
                        IQueryable<Contracts> query = model.Contracts;

                        if (GetArgs.ItemSearch.Value == "Num")
                        {
                            query = query
                                .Where(c => EF.Functions.Like(c.Num, pattern))
                                .Order(c => c.Num, GetArgs.SortOrder);
                        }
                        else if (GetArgs.ItemSearch.Value == "Salary")
                        {
                            query = query
                                .Where(c => EF.Functions.Like(c.Salary.ToString(), pattern))
                                .Order(c => c.Salary, GetArgs.SortOrder);
                        }
                        else if (GetArgs.ItemSearch.Value == "DateConclusion")
                        {
                            query = query
                                .Where(c => EF.Functions.Like(c.DateConclusion.ToLongDateString(), pattern))
                                .Order(c => c.DateConclusion, GetArgs.SortOrder);
                        }
                        else if (GetArgs.ItemSearch.Value == "DateStartWork")
                        {
                            query = query
                                .Where(c => EF.Functions.Like(c.DateStartWork.ToLongDateString(), pattern))
                                .Order(c => c.DateStartWork, GetArgs.SortOrder);
                        }
                        else if (GetArgs.ItemSearch.Value == "DateEndWork")
                        {
                            query = query
                                .Where(c => EF.Functions.Like(c.DateEndWork.ToLongDateString(), pattern))
                                .Order(c => c.DateEndWork, GetArgs.SortOrder);
                        }
                        else if (GetArgs.ItemSearch.Value == "Worker")
                        {
                            query = query
                                .Where(c => EF.Functions.Like(c.WorkerNavigation.FullName, pattern))
                                .Order(c => c.WorkerNavigation.FullName, GetArgs.SortOrder);
                        }
                        else if (GetArgs.ItemSearch.Value == "IdWorker")
                        {
                            query = query
                                .Where(c => EF.Functions.Like(c.WorkerNavigation.Id.ToString(), pattern))
                                .Order(c => c.WorkerNavigation.Id, GetArgs.SortOrder);
                        }
                        else if (GetArgs.ItemSearch.Value == "KindWork")
                        {
                            query = model.ListKindWorks
                                .Where(c => EF.Functions.Like(c.IdKindWorkNavigation.Short, pattern))
                                .Order(c => c.IdKindWorkNavigation.Short, GetArgs.SortOrder)
                                .Select(c => c.IdContractNavigation);
                        }

                        else if (GetArgs.ItemSearch.Value == "Subject")
                        {
                            query = model.ListSubjects
                                .Where(c => EF.Functions.Like(c.IdSubjectNavigation.Short, pattern))
                                .Order(c => c.IdSubjectNavigation.Short, GetArgs.SortOrder)
                                .Select(c => c.IdContractNavigation);
                        }

                        Count = query.Count();

                        list = query
                            .Skip(Page * Size)
                            .Take(Size)
                            .Select(c => new ContractTableRow
                            {
                                IdContract = c.Id,
                                Num = c.Num,
                                DateConclusion = c.DateConclusion.ToLongDateString(),
                                DateStartWork = c.DateStartWork.ToLongDateString(),
                                DateEndWork = c.DateEndWork.ToLongDateString(),
                                Salary = c.Salary,

                                Worker = new Item { Id = c.Worker, Value = c.WorkerNavigation.FullName },
                                KindWork = c.ListKindWorks.Select(y => new ItemLong { Id = y.IdKindWork, Title = y.IdKindWorkNavigation.Title, Short = y.IdKindWorkNavigation.Short }),
                                Subject = c.ListSubjects.Select(y => new ItemLong { Id = y.IdSubject, Title = y.IdSubjectNavigation.Title, Short = y.IdSubjectNavigation.Short })
                            }).ToList();
                    }
                }
                catch (Exception ex)
                {
                    ShowMessage.Error(string.Format("Во время поиска произошла ошибка.\n\n{0} {1}",
                        ex.Message, ex.InnerException.Message));
                }



                stopwatch.Stop();
                logger.Debug("Поиск договора: {0}", stopwatch.Elapsed);

                return list;
            }
        }

    }

    public class WorkerModel : TableModel<WorkerTableRow>
    {
        internal SearchModel GetSearch { get; set; }

        public WorkerModel()
        {
            Size = Properties.Settings.Default.TableWorkerSize;
            GetSearch = new SearchModel();
        }

        internal override bool Delete(int id)
        {
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();

            bool result = true;

            try
            {
                using (ModelContext model = new ModelContext())
                {
                    Workers w = model.Workers.Single(x => x.Id == id);
                    model.Remove(w);
                    model.SaveChanges();
                }
                Count--;
            }
            catch (Exception ex)
            {
                result = false;
                ShowMessage.Error(string.Format(
                    "Во время удаления данных работника из базы данных произошла ошибка. ID работника: {0}\n\n{1} {2}",
                    id, ex.Message, ex.InnerException.Message), "Исключение - MainModel.DeleteContract");
            }

            stopwatch.Stop();
            logger.Debug("DeleteWorker(): {0}", stopwatch.Elapsed);
            return result;
        }
        internal override List<WorkerTableRow> LoadPage()
        {
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();

            List<WorkerTableRow> source = null;
            try
            {
                using (ModelContext model = new ModelContext())
                {

                    Count = model.Workers.Count();

                    IEnumerable<WorkerTableRow> rows = model.Workers
                        .OrderByDescending(r => r.Id)
                        .Skip(Page * Size)
                        .Take(Size)
                        .Select(w => new WorkerTableRow
                        {
                            IdWorker = w.Id,
                            FullName = w.FullName,
                            PassportNumber = w.PassportNumber,
                            PassportSeries = w.PassportSeries,
                            Address = w.Address,
                            BankAccount = w.BankAccount,
                            DateIssued = w.DateIssued.ToLongDateString(),

                            Issued = new ItemLong { Id = w.IssuedNavigation.Id, Short = w.IssuedNavigation.ShortTitle, Title = w.IssuedNavigation.Title },
                            BankItem = new ItemLong { Id = w.BankNavigation.Id, Short = w.BankNavigation.ShortTitle, Title = w.BankNavigation.Title },
                        });

                    source = rows.ToList();
                }
            }
            catch (Exception ex)
            {
                source = null;
                ShowMessage.Error(string.Format(
                    "Во время загрузки страницы с данными работников произошла ошибка. Номер страницы: {0} (отсчет от {1})\n\n{2} {3}",
                    Page, MinPage, ex.Message, ex.InnerException.Message), "Исключение - MainModel.LoadPage");
            }

            stopwatch.Stop();
            logger.Debug("Load page: {0}", stopwatch.Elapsed);

            return source;
        }
        internal override List<WorkerTableRow> Find(SearchArgs e)
        {
            return GetSearch.FirstPage(e);
        }
        internal override List<WorkerTableRow> ReloadPage()
        {
            GetSearch.IsSearch = false;
            return base.ReloadPage();
        }

        internal class SearchModel : SearchModel<WorkerTableRow>
        {
            public SearchModel()
            {
                Size = Properties.Settings.Default.TableSearchSize;
                ListTypeSearch = new List<ItemSearch>
                {
                    new ItemSearch { Value = "Id", Display = "ID" },
                    new ItemSearch { Value = "FullName", Display = "ФИО" },
                    new ItemSearch { Value = "PassportSeries", Display = "Серия паспорта" },
                    new ItemSearch { Value = "PassportNumber", Display = "Личный номер" },
                    new ItemSearch { Value = "DateIssued", Display = "Дата выдачи" },
                    new ItemSearch { Value = "Address", Display = "Адрес" },
                    new ItemSearch { Value = "BankAccount", Display = "Счет" }
                };

                GetItemIdWorker = ListTypeSearch[0];
            }



            internal override List<WorkerTableRow> LoadPage()
            {
                Stopwatch stopwatch = new Stopwatch();
                stopwatch.Start();

                string pattern = GetPattern(GetArgs.IsExactMatch, GetArgs.Keyword);
                List<WorkerTableRow> list = null;

                try
                {
                    using (ModelContext model = new ModelContext())
                    {
                        IQueryable<Workers> query = model.Workers;

                        if (GetArgs.ItemSearch.Value == "Id")
                            query = query
                                .Where(w => EF.Functions.Like(w.Id.ToString(), pattern))
                                .Order(w=>w.Id, GetArgs.SortOrder);

                        else if (GetArgs.ItemSearch.Value == "FullName")
                            query = query
                                .Where(w => EF.Functions.Like(w.FullName, pattern))
                                .Order(w=>w.FullName, GetArgs.SortOrder);

                        else if (GetArgs.ItemSearch.Value == "PassportSeries")
                            query = query
                                .Where(w => EF.Functions.Like(w.PassportSeries, pattern))
                                .Order(w => w.PassportSeries, GetArgs.SortOrder);

                        else if (GetArgs.ItemSearch.Value == "PassportNumber")
                            query = query
                                .Where(w => EF.Functions.Like(w.PassportNumber, pattern))
                                .Order(w => w.PassportNumber, GetArgs.SortOrder);

                        else if (GetArgs.ItemSearch.Value == "Address")
                            query = query
                                .Where(w => EF.Functions.Like(w.Address, pattern))
                                .Order(w => w.Address, GetArgs.SortOrder);

                        else if (GetArgs.ItemSearch.Value == "BankAccount")
                            query = query
                                .Where(w => EF.Functions.Like(w.BankAccount, pattern))
                                .Order(w => w.BankAccount, GetArgs.SortOrder);

                        else if (GetArgs.ItemSearch.Value == "DateIssued")
                            query = query
                                .Where(w => EF.Functions.Like(w.DateIssued.ToLongDateString(), pattern))
                                .Order(w => w.DateIssued, GetArgs.SortOrder);

                        Count = query.Count();

                        list = query
                            .Skip(Page * Size)
                            .Take(Size)
                            .Select(w => new WorkerTableRow
                            {
                                IdWorker = w.Id,
                                FullName = w.FullName,
                                PassportNumber = w.PassportNumber,
                                PassportSeries = w.PassportSeries,
                                Address = w.Address,
                                BankAccount = w.BankAccount,
                                DateIssued = w.DateIssued.ToLongDateString(),

                                Issued = new ItemLong { Id = w.IssuedNavigation.Id, Short = w.IssuedNavigation.ShortTitle, Title = w.IssuedNavigation.Title },
                                BankItem = new ItemLong { Id = w.BankNavigation.Id, Short = w.BankNavigation.ShortTitle, Title = w.BankNavigation.Title },
                            }).ToList();
                    }
                }
                catch (Exception ex)
                {
                    ShowMessage.Error(string.Format("Во время поиска произошла ошибка.\n\n{0} {1}",
                        ex.Message, ex.InnerException.Message));
                }

                stopwatch.Stop();
                logger.Debug("Поиск работника: {0}", stopwatch.Elapsed);

                return list;
            }
        }
    }


    public abstract class TableModel<T> : PagedModelBase<T>
    {
        internal void Added()
        {
            Count++;
        }
        internal abstract bool Delete(int id);
        internal abstract List<T> Find(SearchArgs e);
    }

    public abstract class SearchModel<T> : PagedModelBase<T>
    {
        private bool isSearch;
        internal bool IsSearch
        {
            get { return isSearch; }
            set
            {
                isSearch = value;
                Button[2] = IsSearch;
            }
        }
        internal ItemSearch GetItemIdWorker { get; set; }


        internal List<ItemSearch> ListTypeSearch { get; set; }
        internal string GetSeachResultText
        {
            get
            {
                string text;
                if (Count == 0)
                {
                    text = string.Empty;
                }
                else
                {
                    text = string.Format("Найдено: {0}", Count);
                }
                return text;
            }
        }

        internal List<T> FirstPage(SearchArgs e)
        {
            GetArgs = e;
            List<T> list = FirstPage();
            if (list.Count > 0)
            {
                IsSearch = true;
                PageNumText = GetPageNumText;
                ResultSearchText = GetSeachResultText;
            }
            return list;
        }
        internal string GetPattern(bool exactMatch, string text)
        {
            if (!exactMatch)
            {
                text = string.Format("%{0}%", text);
            }
            return text;
        }
    }

    public abstract class PagedModelBase<T> : ToolStripUI
    {
        internal Logger logger = NLog.LogManager.GetCurrentClassLogger();

        internal event EventHandler InnerChangePageEvent;


        private int count;
        private int page = -1;
        private int maxPage = 1;


        internal int MaxPage
        {
            get { return maxPage; }
            set
            {
                maxPage = value;

                if (Page >= MaxPage)
                {
                    Page = MaxPage - 1;
                    InnerChangePageEvent?.Invoke(this, EventArgs.Empty);
                }
                else if (Page == MaxPage - 1)
                {
                    Button[1] = false;
                }
                else
                {
                    Button[1] = true;
                }
            }
        }
        internal int MinPage { get; }
        internal int Count
        {
            get { return count; }
            set
            {
                count = value;
                if (Count > 0)
                {
                    MaxPage = GetMaxPage();
                }
                PageNumText = GetPageNumText;
            }
        }
        internal int Size { get; set; }
        internal int Page
        {
            get { return page; }
            set
            {
                if (value <= MinPage)
                {
                    page = MinPage;
                    Button[0] = false;
                }
                else
                {
                    page = value;
                    Button[0] = true;
                }
            }
        }
        private int GetMaxPage()
        {
            return Convert.ToInt32(Math.Ceiling((double)Count / Size));
        }
        internal string GetPageNumText
        {
            get { return string.Format("{0} из {1}", Page + 1, MaxPage); }
        }


        internal virtual List<T> ReloadPage()
        {
            return LoadPage();
        }
        internal List<T> FirstPage()
        {
            return CustomPage(MinPage);
        }
        internal List<T> LastPage()
        {
            return CustomPage(MaxPage - 1);
        }
        internal List<T> NextPage()
        {
            return CustomPage(Page + 1);
        }
        internal List<T> PreviousPage()
        {
            return CustomPage(Page - 1);
        }
        internal List<T> CustomPage(int customPage)
        {
            List<T> list;

            Page = customPage;
            list = LoadPage();

            return list;
        }


        internal abstract List<T> LoadPage();
    }

    public class ToolStripUI
    {
        public bool[] Button { get; set; } = new bool[3];
        public SearchArgs GetArgs { get; set; } = new SearchArgs(null, Properties.Settings.Default.ResultSearch_SortDirectionDefault, false, string.Empty);
        public string PageNumText { get; set; }
        public string ResultSearchText { get; set; } = string.Empty;
    }

    public class SearchArgs : EventArgs
    {
        public ItemSearch ItemSearch;
        public SortOrder SortOrder;
        public bool IsExactMatch;
        public string Keyword;

        public SearchArgs(ItemSearch item, SortOrder order, bool match, string keyword)
        {
            ItemSearch = item;
            SortOrder = order;
            IsExactMatch = match;
            Keyword = keyword;
        }
    }

UPDATE

In connection with the continuation of the development, updated the classes code to the actual state. The changes affect part of the search and have almost no effect on the interaction of classes. In addition to reducing duplicate values. So in ToolStripUI appeared one property GetArgs, which contains data from SearchArgs.

UPDATE

My topic don't correct? No any comment and answer on theme.

\$\endgroup\$
  • 1
    \$\begingroup\$ There is something missing here: ... // Likewise - please post all code. \$\endgroup\$ – t3chb0t Jul 21 at 9:56
  • 1
    \$\begingroup\$ Please tag the relevant technology (winforms,...) instead of using such general tags as "object oriented" or "inheritance". \$\endgroup\$ – BCdotWEB Jul 21 at 10:03
  • \$\begingroup\$ @BCdotWEB this is really winforms, but others are specific (e.g., LINQ), are not relevant to the subject matter. It should be specified? \$\endgroup\$ – Owl Jul 21 at 10:30
  • \$\begingroup\$ @t3chb0t SearchTable* and Table* - are essentially the same. The difference is in referring to another table whose names differ according to Contract and Worker \$\endgroup\$ – Owl Jul 21 at 10:32
1
\$\begingroup\$

Inheritance

  • the point of inheritance and abstract base classes or interfaces is to have a common API that each type implements in its own way. Your inhertiance model doesn't do that. Classes that are inherited from the PageModelBase add a lot new APIs like the SearchModel. Some of them like the FirstPage method even gets a new overload. This is very confusing. It's difficult to figre out how these models are used but they definitely shouldn't be based on PageModelBase.
  • the abstract class PagedModelBase doesn't have any abstract or virtual methods so there is not reason for it to be abstract because you don't override anything. It looks like it should be a PageNavigator that other classes use as a service/dependency. In other words, you cannot use the SearchModel where you currently use TableModel because even though they share a common base class, they are not exchangable as they use additionl and specialized APIs.

Repetitions

internal override List<ContractTableRow> LoadPage()
{
  Stopwatch stopwatch = new Stopwatch();
  stopwatch.Start();

  // do soemthing...

  stopwatch.Stop();
  logger.Debug("Поиск договора: {0}", stopwatch.Elapsed);

  return list;
}
  • you use this pattern in a lot of places. It'd better to create a benchmark-helper or even a decorator for your models that would add this layer outside the core APIs.
  • you can instantly start with Stopwatch.StartNew()
  • there's no need to stop it, just call stopwatch.Elapsed

Misc

  • some of the names are confusing like where you write SearchArgs GetArgs. This property should also be called SearchArgs
  • I cannot find any event SearchChanged<SearchArgs> so I think you are not using it with an event. If this is true, then you shouldn't be using EventArgs as its base class because there is no benefit in doing so.
  • using var instead of full types would make your code less verbose and consequently easier to read
  • ContractModel.Delete (and others) returns a bool but more useful would be to return the number of affected rows that SaveChanges returns. bool doesn't tell me whether anything has actually been deleted, only that the method didn't fail. This is rarely useful.
  • you decrease Count-- after a deletion without actually checking if anything has been really deleted. You should check what SaveChanges returs.
  • I don't think that models should use the static ShowMessage type. It should be a service that is injected via the constructor.
  • you should use constants for all the magic-strings like "Num" or "Salary" etc.
\$\endgroup\$
  • \$\begingroup\$ The first item came out in my opinion too general. I don't quite understand him. Regarding the second, there is abstract List<T> LoadPage() and virtual List<T> ReloadPage(). About Stopwatch: I don't have enough skills to create such 'helpers'. Event SearchArgs really missing. Due to the modification of the code, which was discussed in the topic update. Count-- has no checks because the method Delete() is called based on the result true from another method Delete() (outside this model). \$\endgroup\$ – Owl Jul 27 at 18:18
  • \$\begingroup\$ @Owl oh, I now see the beginner tag... I'll try to improve my answer... \$\endgroup\$ – t3chb0t Jul 27 at 19:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.