Home > Software design >  Set value of model property on first hand
Set value of model property on first hand

Time:07-23

I have a stored procedure that returns a simple list of 3 columns:

ItemGroup
Weight
Price

I have a model like this:

public class MyViewModel
{
    ...
    public IList<MyItemViewModel> Items { get; set; } = new List<MyItemViewModel>();

    public MyViewModel AssignItems(IEnumerable<MyItemViewModel> model)
    {
        if (model is null) 
            return this;

        ((List<MyItemViewModel>)Items).AddRange(model);
        return this;
    }
}

MyItemViewModel:

public class MyItemViewModel
{
    public string ItemGroup { get; set; }
    public decimal Weight { get; set; }
    public decimal Price { get; set; }
}

I populate the list correctly, now I want to add some properties to MyItemViewModel in order to have each property assigned when it's being populated, so I try to do something like:

public class MyItemViewModel
{
    public string ItemGroup { get; set; }
    public decimal Weight { get; set; }
    public decimal Price { get; set; }

    // Pseudocode
    public decimal SteelWeight { get; set; } => Weight != null ? Weight.Where(ItemGroup == "Steel"): 0
    public decimal SteelPrice { get; set; } => Price != null ? Price.Where(ItemGroup == "Steel") : 0
    public decimal DevicesWeight { get; set; } => Weight != null ? Weight.Where(ItemGroup == "Devices") : 0
    public decimal DevicesPrice { get; set; } => Price != null ? Price.Where(ItemGroup == "Devices") : 0
}

Now I get this error:

Block bodies and expression bodies cannot both be provided.

So, the expected result of the new properties is to set into them the Weight and Price value where ItemGroup value equals to specific string. How can I achieve that?

Extra scope: I want to do that because I want to replace that properties on a html template as:

  var html = await System.IO.File.ReadAllTextAsync($"{_webHostEnvironment.WebRootPath}/documentTemplates/myTemplate.html");

  html = html.Replace("steelWeight".TokenizeWithBrackets(), $"{rModel.Items.SteelWeight}")
  //etc...

CodePudding user response:

First off, the error you're getting is because, as it states, you can't use both the get; set; syntax for a property, and also use a => to point to an expression. Essentially, you're defining the "get" action twice!

Go back to what you probably had to start with:

public class MyItemViewModel
{
    public string ItemGroup { get; set; }
    public decimal Weight { get; set; }
    public decimal Price { get; set; }

    //Pseudocode
    public decimal SteelWeight { get; set; }
    public decimal SteelPrice { get; set; } 
    public decimal DevicesWeight { get; set; } 
    public decimal DevicesPrice { get; set; }
}

Now, as for fetching the values of a particular MyItemViewModel:

This would be a two-part operation: first, find the MyItemViewModel instance you want, from the collection in MyViewModel, and then retrieve the particular Weight and Price you need.

The code would be something like this:

MyViewModel myViewModel = <whatever it takes to get an instance of this>;
MyItemViewModel target = myViewModel
                            .Items
                            .SingleOrDefault(item => item.ItemGroup == "Steel");
// I'm assuming the true destination of these values is somewhere else
// and not a property of the individual MyItemViewModel instance.

var steelWeight = target?.Weight ?? 0;
var price = target?.Price ?? 0;

Note that the above (which was from memory) assumes that there's only one item in myViewModel.Items for every value of ItemGroup. If there's more than one, SingleOrDefault won't work and you'll have to use FirstOrDefault or some other method.

Also, I allowed for the possibility that you might have no items in MyViewModel.Items that matched "Steel".

ETA: Here's a suggestion: give the MyViewModel class a new method: GetByItemGroup:

public MyItemViewModel GetByItemGroup(string itemGroup) 
{
    return this.Items.SingleOrDefault(item => item.ItemGroup == itemGroup);
}

Then you can use it like this in your code:

MyViewModel myViewModel = ....;
var steelItem = myViewModel.GetByItemGroup("Steel");
var devicesItem = myViewModel.GetByItemGroup("Devices");

// Actually use the data:
targetHtml = targetHtml.Replace("steel-weight", $"{steelItem?.Weight ?? 0}");
targetHtml = targetHtml.Replace("steel-price", $"{steelItem?.Price ?? 0}");
targetHtml = targetHtml.Replace("devices-weight", $"{devicesItem?.Weight ?? 0}");
... etc.
  • Related