PopulateWithNonDefaultValues() nested object behaviour

One of my favourite servicestack methods is PopulateWithNonDefaultValues() it saves a lot of time updating existing objects in PATCH requests and such but I just debugged an issue where it is not working consistently.

Take this code:

public class Program
{
	public static void Main()
	{		
		var existing = new MyObj
		{
			Id = 123,
			Name = "Test",
			Data = "data",
			Nested = new MyNestedObj
			{
				Id = 456,
				Name = "Test nested",
				Data = "data nested",
			}
				
		};
		
		var update = new MyObj
		{
			Id = 0,
			Name = "Test",
			Data = "different",
			Nested = new MyNestedObj
			{
				Id = 0,
				Name = "Test nested",
				Data = "data nested different",
			}
		};
		
		var newObj = existing.PopulateWithNonDefaultValues(update);
		
		Console.WriteLine(newObj.Id); // Output: 123
		Console.WriteLine(newObj.Nested.Id); //Output: 0
	}
}

public class MyObj
{
	public int Id {get; set;}
	public string Name {get; set;}
	public string Data {get; set;}
	public MyNestedObj Nested {get;set;}
}

public class MyNestedObj
{
	public int Id {get; set;}
	public string Name {get; set;}
	public string Data {get; set;}
}

Why does it ignore the default value for parent object but then replace the nested items Id with the default value?

I use this in conjunction with OrmLite so any place I save using it to update, the nested object doesn’t work because that object loses it’s Id.

Is this meant to work like this?

I looked at docs and saw there is PopulateFromPropertiesWithoutAttribute() so I tried this:

public class Program
{
	public static void Main()
	{		
		var existing = new MyObj
		{
			Id = 123,
			Name = "Test",
			Data = "data",
			Nested = new MyNestedObj
			{
				Id = 123,
				Name = "Test nested",
				Data = "data nested",
			}
				
		};
		
		var update = new MyObj
		{
			Id = 0,
			Name = "Test",
			Data = "different",
			Nested = new MyNestedObj
			{
				Id = 0,
				Name = "Test nested",
				Data = null,
			}
		};
		
		var newObj = existing.PopulateFromPropertiesWithoutAttribute(update, typeof(DontPopulate));
		
		Console.WriteLine(newObj.Id);  //0
		Console.WriteLine(newObj.Nested.Id);  //0
		Console.WriteLine(newObj.Nested.Data); //no output
	}
}

public class MyObj
{
	public int Id {get; set;}
	public string Name {get; set;}
	public string Data {get; set;}
	public MyNestedObj Nested {get;set;}
}

public class MyNestedObj
{
	[DontPopulate]
	public int Id {get; set;}
	public string Name {get; set;}
	public string Data {get; set;}
}

public class DontPopulate : AttributeBase { }

But now confusingly both Id’s output as 0 even though only the nested object has attribute and also null values overwrite the original so its not good for PATCH type operations.

Is there anyway to get this working nicely with nested objects so it doesn’t 0 the Ids or replace properties with null?

To be honest there might be times when 0 is a valid value for other properties, I just want to make sure Ids dont get zeroed and null doesn’t overwrite a value. Is that possible?

I thought this through some more and it obviously can’t match up the nested properties and just replaces the property value entirely if it is not null as it doesn’t know which field to match them on. I hadn’t given it proper thought.

I will add custom logic to the populator for dealing with nested objects, sorry to bother you.

1 Like