Использование дочернего свойства в родительских методах - PullRequest
0 голосов
/ 18 апреля 2019

У меня есть много классов моделей, которые я заполняю данными, извлеченными из службы веб-API. Все классы имеют много общих свойств, таких как дата создания и т. Д.

public class Car
    {
        public int CarId { get; set; }
        [Browsable(false)]
        public int CreatedBy { get; set; }
        [DisplayName("Utworzył")]
        public string CreatedByName { get; set; }
        [DisplayName("Data utworzenia")]
        public DateTime CreatedOn { get; set; }
        [Browsable(false)]
        public int? LmBy { get; set; }
        [DisplayName("Zmodyfikował")]
        public string LmByName { get; set; }
        [DisplayName("Data modyfikacji")]
        public DateTime? LmOn { get; set; }
        [Browsable(false)]
        public int TenantId { get; set; }
        [Browsable(false)]
        public string TenantName { get; set; }
    }

Все классы моделей также имеют методы для создания / обновления связанных сущностей в БД. Например, методы класса «Car»:

public async Task<bool> Add()
        {
            using (var client = new HttpClient())
            {
                string url = Secrets.ApiAddress + $"CreateCar?token=" + Secrets.TenantToken + "&UserId=" + RuntimeSettings.UserId;
                var serializedProduct = JsonConvert.SerializeObject(this);
                var content = new StringContent(serializedProduct, Encoding.UTF8, "application/json");
                var result = await client.PostAsync(new Uri(url), content);
                if (result.IsSuccessStatusCode)
                {
                    var rString = await result.Content.ReadAsStringAsync();
                    T _this = JsonConvert.DeserializeObject<T>(rString);
                    this.CarId = _this.CarId;
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }

        public async void Edit()
        {
            using (var client = new HttpClient())
            {
                string url = Secrets.ApiAddress + $"EditCar?token=" + Secrets.TenantToken + "&id={0}&UserId={1}";
                var serializedProduct = JsonConvert.SerializeObject(this);
                var content = new StringContent(serializedProduct, Encoding.UTF8, "application/json");
                var result = await client.PutAsync(String.Format(url, this.CarId, RuntimeSettings.UserId), content);
            }
        }

Так что я подумал, что было бы неплохо создать один класс моделей для всех остальных. Он будет иметь все общие свойства:

public abstract class Entity<T>
    {
        [Browsable(false)]
        public int CreatedBy { get; set; }
        [DisplayName("Utworzył")]
        public string CreatedByName { get; set; }
        [DisplayName("Data utworzenia")]
        public DateTime CreatedOn { get; set; }
        [Browsable(false)]
        public int? LmBy { get; set; }
        [DisplayName("Zmodyfikował")]
        public string LmByName { get; set; }
        [DisplayName("Data modyfikacji")]
        public DateTime? LmOn { get; set; }
        [Browsable(false)]
        public int TenantId { get; set; }
        [Browsable(false)]
        public string TenantName { get; set; }
    }

Это будет использоваться, как показано ниже:

public class Car : Entity<Car>
    {
        public int CarId { get; set; }
    }

У меня проблема с методами. Если я сохраню их в родительском классе (а не для того, чтобы создавать их для каждого дочернего элемента, поскольку 90% логики используется совместно), я не могу использовать свойство идентификатора дочернего элемента (CarId) в родительских методах просто потому, что такие свойства не существуют в родительском:

public async Task<bool> Add()
        {
            using (var client = new HttpClient())
            {
                string url = Secrets.ApiAddress + $"Create{typeof(T).Name}?token=" + Secrets.TenantToken + "&UserId=" + RuntimeSettings.UserId;
                var serializedProduct = JsonConvert.SerializeObject(this);
                var content = new StringContent(serializedProduct, Encoding.UTF8, "application/json");
                var result = await client.PostAsync(new Uri(url), content);
                if (result.IsSuccessStatusCode)
                {
                    var rString = await result.Content.ReadAsStringAsync();
                    T _this = JsonConvert.DeserializeObject<T>(rString);
                    this.CarId = _this.CarId; // CarId doesn't exist in parent, it's child's property
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }

        public async void Edit()
        {
            using (var client = new HttpClient())
            {
                string url = Secrets.ApiAddress + $"Edit{typeof(T).Name}?token=" + Secrets.TenantToken + "&id={0}&UserId={1}";
                var serializedProduct = JsonConvert.SerializeObject(this);
                var content = new StringContent(serializedProduct, Encoding.UTF8, "application/json");
                var result = await client.PutAsync(String.Format(url, this.CarId, RuntimeSettings.UserId), content); // CarId doesn't exist in parent, it's child's property
            }
        }

Вероятно, если бы я использовал более общие имена свойств идентификатора (Id вместо CarId), это было бы проще, но предполагая, что я должен придерживаться пользовательских имен ("CarId", "EmployeeId") - каков мой выбор?

Может быть, я мог бы создать универсальное свойство ID в parent и каким-то образом связать его с соответствующим полем id ребенка, когда я наследую?

Ответы [ 4 ]

0 голосов
/ 25 апреля 2019

Я решил это путем реализации небольшого обходного пути. «Правка» сработала, когда я применил предложение HimBromBeere. Чтобы «Добавить» работал, мне пришлось изменить свой класс сущностей на:

public abstract class Entity<T>
    {
        [Browsable(false)]
        public string AddedItem { get; set; }

        public virtual async Task<bool> Add()
        {
            using (var client = new HttpClient())
            {
                string url = Secrets.ApiAddress + $"Create{typeof(T).Name}?token=" + Secrets.TenantToken + "&UserId=" + RuntimeSettings.UserId;
                var serializedProduct = JsonConvert.SerializeObject(this);
                var content = new StringContent(serializedProduct, Encoding.UTF8, "application/json");
                var result = await client.PostAsync(new Uri(url), content);
                if (result.IsSuccessStatusCode)
                {
                    var rString = await result.Content.ReadAsStringAsync();
                    AddedItem = rString;
                    return true;
                }
                else
                {
                    MessageBox.Show("Serwer zwrócił błąd przy próbie utworzenia rekordu. Wiadomość: " + result.ReasonPhrase);
                    return false;
                }
            }
        }
    }

И производный класс был изменен на:

public class Car : Entity<Car>
    {
        public async override Task<bool> Add()
        {
            bool x = await base.Add();
            if (x)
            {
                try
                {
                    Car _this = JsonConvert.DeserializeObject<Car>(AddedItem);
                    this.CarId = _this.CarId;
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }

                MessageBox.Show("Tworzenie nowego rekordu zakończone powodzeniem!");
                return true;
            }
            else
            {
                return false;
            }
        }
    }

Я нашел ответ HimBromBeere наиболее полезным и поэтому выбрал его пост как ответ на мой вопрос.

0 голосов
/ 18 апреля 2019

Идея суперкласса abstract была абсолютно хорошей.Однако это не должно быть универсальным.Он должен просто содержать все общее поведение.Сказав это, ваш Entitity -класс также должен иметь abstract ID -property:

public abstract class Entity
{
    [Browsable(false)]
    public int CreatedBy { get; set; }
    [DisplayName("Utworzył")]
    public string CreatedByName { get; set; }
    [DisplayName("Data utworzenia")]
    public DateTime CreatedOn { get; set; }
    [Browsable(false)]
    public int? LmBy { get; set; }
    [DisplayName("Zmodyfikował")]
    public string LmByName { get; set; }
    [DisplayName("Data modyfikacji")]
    public DateTime? LmOn { get; set; }
    [Browsable(false)]
    public int TenantId { get; set; }
    [Browsable(false)]
    public string TenantName { get; set; }
    public abstract int Id { get; set; }
}

Теперь в вашем реализующем классе вы можете реализовать свойство abstract для возврата конкретного CarId, например:

public class Car : Entity
{
    public int CarId { get; set; }
    public int Id => CarId;
}

В качестве альтернативы вы можете полностью опустить свойство CarId из вашего Car -класса и иметь только Id из абстрактного класса:

public class Car : Entity
{
    public int Id get; set; }
}

Нетнезависимо от того, какой из этих двух подходов вы выбрали, ваш базовый класс теперь имеет и Id -члена, благодаря чему ваш Add -метод выглядит следующим образом:

public async Task<bool> Add()
{
    using (var client = new HttpClient())
    {
        string url = Secrets.ApiAddress + $"Create{this.GetType().Name}?token=" + Secrets.TenantToken + "&UserId=" + RuntimeSettings.UserId;
        var serializedProduct = JsonConvert.SerializeObject(this);
        var content = new StringContent(serializedProduct, Encoding.UTF8, "application/json");
        var result = await client.PostAsync(new Uri(url), content);
        if (result.IsSuccessStatusCode)
        {
            var rString = await result.Content.ReadAsStringAsync();
            // you don´t need to knoe the actual type, all you need is its Id, so an Entity is just fine
            Entity e = JsonConvert.DeserializeObject(rString);
            this.Id = e.Id; 
            return true;
        }
        else
        {
            return false;
        }
    }
}
0 голосов
/ 18 апреля 2019

Возможно, вы захотите взглянуть на шаблон хранилища.В шаблоне репозитория создайте базовый репозиторий с базовыми операциями CRUD над свойствами в вашем абстрактном классе Entity.Затем создайте производные классы репозитория для операций со свойствами, специфичными для сущностей.Если вы все еще хотите заниматься в модельных классах, вы можете сделать это, как показано ниже.

public abstract class Entity<T>
    {
        [Browsable(false)]
        public int CreatedBy { get; set; }
        [DisplayName("Utworzył")]
        public string CreatedByName { get; set; }
        [DisplayName("Data utworzenia")]
        public DateTime CreatedOn { get; set; }
        [Browsable(false)]
        public int? LmBy { get; set; }
        [DisplayName("Zmodyfikował")]
        public string LmByName { get; set; }
        [DisplayName("Data modyfikacji")]
        public DateTime? LmOn { get; set; }
        [Browsable(false)]
        public int TenantId { get; set; }
        [Browsable(false)]
        public string TenantName { get; set; }
        public virtual void Add(){
//operation using base properties
         }

public class Car : Entity<Car>
    {
        public int CarId { get; set; }
        public override void Add(){
            //do custom operation or call base.Add() or whatever you want
        }
    }

}
0 голосов
/ 18 апреля 2019

Таким образом:

public abstract class Entity
{
    [Browsable(false)]
    public int CreatedBy { get; set; }
    [DisplayName("Utworzył")]
    public string CreatedByName { get; set; }
    [DisplayName("Data utworzenia")]
    public DateTime CreatedOn { get; set; }
    [Browsable(false)]
    public int? LmBy { get; set; }
    [DisplayName("Zmodyfikował")]
    public string LmByName { get; set; }
    [DisplayName("Data modyfikacji")]
    public DateTime? LmOn { get; set; }
    [Browsable(false)]
    public int TenantId { get; set; }
    [Browsable(false)]
    public string TenantName { get; set; }
}


public class Car : Entity
{
    public int CarId { get; set; }
}

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

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