how to Add nested object models to the list? - c#

I have some object models like this :
var x= new XModel()
{
end_date = "2017-12-15",
page = 1,
start_date = "2014-12-01",
group_by = new List<string> { "numbers" },
filter = new Filter() { numbers= new List<int> {1620} ,names= null, deleted= null, added = null }
};
or this one :
var y= new YModel
{
Title = "test title",
GenderType = Gender.Men,
Oss = "ALL",
Devices = new List<string> { "11", "12" },
Categories = new List<string> { "11", "12" },
}
i want to add these models to the list, the problem is , i tried to wrote a generic method to add all object models like above to the list.
My current method is :
internal static List<UrlParameter> GetParams<TModel>(this TModel entity)
{
var parameters = new List<UrlParameter>();
foreach (var propertyInfo in entity.GetType().GetProperties())
{
var propVal = propertyInfo.GetValue(entity, null);
if (propVal == null)
{
parameters.Add(new UrlParameter(propertyInfo.Name, ""));
continue;
}
if (propertyInfo.PropertyType.IsGenericType)
{
if (propVal.GetType().IsPrimitiveType())
{
parameters.Add(new UrlParameter(propertyInfo.Name, propVal));
}
else
{
var arr = propVal as IEnumerable;
if (arr.HasArrayContainPrimitiveType())
parameters.Add(new UrlParameter(propertyInfo.Name, $"[{ToJsonArray(arr)}]"));
else
parameters.AddRange(from object obj in arr
select GetParams(obj)
into subparams
select new UrlParameter(propertyInfo.Name, subparams));
}
}
else
{
if (propVal.GetType().IsPrimitiveType())
parameters.Add(new UrlParameter(propertyInfo.Name, propVal));
else
{
var subparams = GetParams(propVal);
parameters.Add(new UrlParameter(propertyInfo.Name, subparams));
}
}
}
return parameters;
}
it works fine for most of my models, but the x where contains filter makes me a problem, the numbers value saved like this filter=numbers%3d%255b1620%255d%2c%2c%2c%2c%2c%2c%2c , and the rest of the fields disappeare.
i want to add numbers, names, deleted and added as key, value parameter nested in filter, can you please help me to fixed this?

I solved my problem by using MultipartFormDataContent class.
it converts all the nested model as they are.

Related

how to build and return a result from a webapi controler

So I have put together a group of stored procedure calls in my web api controller. Now I need to return the combined results. Javascript is as simple as something like this:
var result = [{
objectResult: value
},{
arryResult1:[value]
},{
arryResult2:[value]
}]
but it c# it would require a class that contains 2 lists and a object? then return that as a list? this is where i am kind of lost.
[HttpPost]
[Route("builderContact")]
public List<usp_get_builder_contact_data_Result> GetBuilderContact(parameter parameter)
{
object[] parameters = { parameter.company_id, parameter.subdivision_id };
var builderContact = db.Database.SqlQuery<usp_get_builder_contact_data_Result>("sandbox.usp_get_builder_contact_data {0},{1}",
parameters).First();
var floorplanDataResult = db.Database.SqlQuery<usp_get_floorplan_data_Result>("sandbox.usp_get_floorplan_data {0},{1}",
parameters).ToList();
var floorplanRelatedResult = db.Database.SqlQuery<usp_get_floorplan_related_sections_Result>("sandbox.usp_get_floorplan_related_sections {0},{1}",
parameters).ToList();
return ?;
}
update for answer
[HttpPost]
[Route("bigEnchilada")]
public List<object> GetBuilderContact(parameter parameter)
{
object[] parameters = { parameter.company_id, parameter.subdivision_id };
var builderContact = db.Database.SqlQuery<usp_get_builder_contact_data_Result>("sandbox.usp_get_builder_contact_data {0},{1}",
parameters).First();
var floorplanDataResult = db.Database.SqlQuery<usp_get_floorplan_data_Result>("sandbox.usp_get_floorplan_data {0},{1}",
parameters).ToList();
var floorplanRelatedResult = db.Database.SqlQuery<usp_get_floorplan_related_sections_Result>("sandbox.usp_get_floorplan_related_sections {0},{1}",
parameters).ToList();
return (new object[] {
new object { builderContact = builderContact },
new object { floorplanDataResult = floorplanDataResult },
new object { floorplanRelatedResult = floorplanRelatedResult }
}).ToList();
}
If you want it to match exactly what you have in Javascript, then change the return type to List<object> and return:
return new List<object> {
new { objectResult = builderContact },
new { arryResult1 = floorplanDataResult },
new { arryResult2 = floorplanRelatedResult }
};
IMHO in this context the following model would be much more suited (if you can change it, that is):
var result = {
objectResult: value,
arryResult1: [value],
arryResult2: [value]
}
In which case you would set the return type to object and return:
return new {
objectResult = builderContact,
arryResult1 = floorplanDataResult,
arryResult2 = floorplanRelatedResult
};
A tiny bit nicer, no?
You can simply concat them all ?
List<object> allItems = (
from x in floorplanDataResult.ToList() select new object()
).ToList().Concat(
from y in floorplanRelatedResult.ToList() select new object()
).ToList();
return allItems;
I don't know if your client expects them in the same payload though...

How to add if statement in anonymous class?

If I have this :
SubMenuList=new object[]
{
new
{
transKey = "PERSONAL_INFORMATION",
stateName="account.personalinformation",
displayUrl = "/account/personalinformation"
},
new
{
tranKey = "NOTIFICATIONS",
stateName = "account.notificationsettings",
displayUrl = "/account/notifications"
}
}
Can I somehow add an if statement to this and say for example:
if (something != null)
{
new
{
transKey = "PERSONAL_INFORMATION",
stateName="account.personalinformation",
displayUrl = "/account/personalinformation"
}
}
For this purpose is better to use List<Object>:
var list = new List<object>
{
new
{
transKey = "PERSONAL_INFORMATION",
stateName="account.personalinformation",
displayUrl = "/account/personalinformation"
}
};
if (something != null)
{
list.Add(new
{
tranKey = "NOTIFICATIONS",
stateName = "account.notificationsettings",
displayUrl = "/account/notifications"
});
}
if you want to get an array, you can invoke ToArray() on the link:
SubMenuList = list.ToArray();
It is better to introduce non anonymous type here, because these objects have the same structure, and without the context it is hard to guess why you do not use named types.
You can use a list with real type, as suggested by #DavidArno, and add the new item to the list if something != null.
You can also use anonymous types:
var list = new[]
{
new
{
transKey = "PERSONAL_INFORMATION",
stateName="account.personalinformation",
displayUrl = "/account/personalinformation"
},
new
{
transKey = "NOTIFICATIONS",
stateName = "account.notificationsettings",
displayUrl = "/account/notifications"
}
}.ToList()
if (something != null)
{
list.Add(new
{
transKey = "PERSONAL_INFORMATION",
stateName="account.personalinformation",
displayUrl = "/account/personalinformation"
});
}
If you don't need to access the members of the anonymous type (e.g. list[0].transKey) or are okay with using reflection, Alex's answer might be better suited for your question.

filtering a tuple based on item 3 in the tuple

I need to print a list of countries that use dollars as a currency from a web service.
the data comes form a class called country services which contains this tuple:
public static IEnumerable<Tuple<string, string, string, string>> GetCountryData()
{
var countryService = new CountryServiceProxy.country();
var xmlStringResult = countryService.GetCurrencies();
var result = new List<Tuple<string, string, string, string>>();
var xPathDoc = new XPathDocument(new XmlTextReader(new StringReader(xmlStringResult)));
var navigator = xPathDoc.CreateNavigator();
var nodes = navigator.Select("//Table");
var nodeNames = new[] {"Name", "CountryCode", "Currency", "CurrencyCode"};
while (nodes.MoveNext())
{
var nodeValues = new[] {string.Empty, string.Empty, string.Empty, string.Empty};
for (var i = 0; i < nodeNames.Length; i++)
{
var node = nodes.Current.SelectSingleNode(nodeNames[i]);
if (node != null)
{
nodeValues[i] = node.Value;
}
}
result.Add(new Tuple<string, string, string, string>(nodeValues[0], nodeValues[1], nodeValues[2], nodeValues[3]));
}
return result;
}
I need to call that method and use it to print out a list with countries that use dollars:
private static IEnumerable<Country> Excercise4()
{
// var data = CountryService.GetCountryData().Where(x => x.Item3.Contains("Dollar"));
// ////var data = CountryService.GetCountryData().Where(x => x.Item3 == "Dollar");
// //Console.WriteLine(data);
return new List<Country>
{
new Country("da", "C1", "$", "Dollar"),
new Country("Country2", "C3", "$", "Dollar")
};
}
so far my method looks like this. i cant seem to figure out how to print out the tuple , havent used tuple before.
my write method is as follows:
ConsoleHelper.PrintCountryResults(Excercise4(), "Return a list of Country objects who's currency is Dollar");
ConsoleHelper.Pause(PauseMessage);
and the console helper class looks like this :
public static void PrintCountryResults(IEnumerable<Country> results, string title)
{
PrintHeader(title);
foreach (var result in results)
{
Console.WriteLine("{0, -30}{1, -5}{2, -15}{3, -5}", result.CountryName, result.CountryCode, result.CurrencyName, result.CurrencyCode);
}
}
any help would be appreciated as i said havent used tuple before first try at them ..
Thanx
You can filter the properties of the tuple by referencing the ItemX property with X being the 1-based index of the property that you're interested in. in you case if the currency is the third item, filtering the tuples would look like
var countriesUsingDollarAsACurrency = GetCountryData().Where(tuple => tuple.Item3 == "Dollar");

Setting null in list cause null value in other list

I have two lists which i want to get the different items from them
SearchElement[] criteria = new SearchElement[] {
new SearchElement
{
Comparison = "=",
FieldName = "CableProperty.ProjectId",
FieldValue = int.Parse(comboBoxSource.SelectedValue.ToString()),
LogicalOperator = "" }
};
sourceCables = client.GetCables(criteria, null, "Cores,CableProperty,CableProperty.CableApplication").ToList();
criteria = new SearchElement[] {
new SearchElement
{
Comparison = "=",
FieldName = "CableProperty.ProjectId",
FieldValue = int.Parse(comboBoxDestination.SelectedValue.ToString()),
LogicalOperator = "" }
};
destinationCables = client.GetCables(criteria, null, "Cores,CableProperty,CableProperty.CableApplication").ToList();
diffCables = sourceCables.Except(destinationCables, new CableComparer())
.ToList();
Now I have the different items in diffcable. Sometimes i want to set
diffCable.CableProperty.CableApplication = null;
but when i do that, all the navigation Porperty(CableApplication) in sourcelist is also set to null.
this is the code
if (destinationCableApplications.Contains(diffCable.CableProperty.CableApplication, new CableApplicationComparer()))
{
criteria = new SearchElement[] { new SearchElement { Comparison = "=", FieldName = "ProjectId", FieldValue = int.Parse(comboBoxDestination.SelectedValue.ToString()), LogicalOperator = "" }};
cableApplication = client.GetCableApplications(criteria, null, "").SingleOrDefault();
diffCable.CableProperty.CableApplication = null;
}
excatly in after this line
diffCable.CableProperty.CableApplication = null;
all the
sourcecables[0].CableProperty.CableApplication
sourcecables[1].CableProperty.CableApplication
.....
sourcecables[100].CableProperty.CableApplication
are set to null
what should i do to not lose the navigation property in sourcelist when i set null to navigation property in diffcable ?
easiest way is using MemoryStream..
Here is a sample,
[Serializable]
public class temp
{
public int a;
}
class Program
{
public static T DeepClone<T>(T a)
{
using (MemoryStream stream = new MemoryStream())
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, a);
stream.Position = 0;
return (T)formatter.Deserialize(stream);
}
}
static void Main(string[] args)
{
List<temp> list1 = new List<temp>();
list1.Add(new temp { a = 1 });
list1.Add(new temp { a = 2 });
list1.Add(new temp { a = 3 });
List<temp> list2 = DeepClone<List<temp>>(list1);
list1[1].a = 4;
Console.WriteLine(list2[1].a);
Console.ReadKey();
}
}
Note: class must be Serializable.
This will work for all value and reference types.
You are doing a copy by reference without realising it. Look into Cloning your objects or creating new lists.
List<int> newCopyList = new List<int>(originalList);

Linq query for searching an object inside a dictionary having list of lists as values

I'm searching a sorted dictionary with a key of type datetime and values as list of objects. What I need to find is the latest value(based on a property on the object) for each object in the dictionary. My object has 3 properties : a name, a value and a date when it was created. My dictionary is sorted by latest date in descending order.
I have got this working somehow, but I'm sure there is a shortcut for this using LINQ. Please note that I'm using .NET 3.5. Could you please help? Please dont get put off by the huge amount code below as I have added it for clarity and i'm only looking for a linq query to query inside a list of list objects.
Code below:
public void Should_link_recent_data_together()
{
var data = TimeSeriesDataFactoryEx.GetData();
var allAttributes = new List<string>()
{
TimeSeriesConstants.TOTAL_COST_CODE,
TimeSeriesConstants.TOTAL_VALUE_CODE,
TimeSeriesConstants.SOURCE_CODE
};
var latestList = new List<TimeSeries>();
var allValues = data.Values.ToList();
#region HOW DO I DO THIS USING LINQ?
bool found = false;
foreach (var attribute in allAttributes)
{
found = false;
foreach (var tsData in allValues)
{
foreach (var ts in tsData)
{
if (ts.MetricName == attribute && !string.IsNullOrEmpty(ts.MetricValue))
{
latestList.Add(ts);
found = true;
break;
}
}
if (found)
break;
}
}
#endregion
Assert.IsTrue(latestList.Count == 3);
Assert.IsTrue(latestList.Where(x => x.MetricName == TimeSeriesConstants.TOTAL_COST_CODE).First().MetricValue == "1");
Assert.IsTrue(latestList.Where(x => x.MetricName == TimeSeriesConstants.TOTAL_VALUE_CODE).First().MetricValue == "2");
Assert.IsTrue(latestList.Where(x => x.MetricName == TimeSeriesConstants.SOURCE_CODE).First().MetricValue == "gp");
Assert.IsTrue(latestList.Where(x => x.MetricName == TimeSeriesConstants.SOURCE_CODE).First().Quarter == DateTime.Today.AddMonths(-3));
}
internal class TimeSeriesDataFactoryEx
{
public static SortedDictionary<DateTime?,List<TimeSeries>> GetData()
{
return new SortedDictionary<DateTime?, List<TimeSeries>>(new DateComparer())
{
{
DateTime.Today, new List<TimeSeries>()
{
new TimeSeries()
{
Quarter = DateTime.Today,
MetricValue = "1",
MetricName = TimeSeriesConstants.TOTAL_COST_CODE
},
new TimeSeries()
{
Quarter = DateTime.Today,
MetricValue = "2",
MetricName = TimeSeriesConstants.TOTAL_VALUE_CODE
},
new TimeSeries()
{
Quarter = DateTime.Today,
MetricValue = "",
MetricName = TimeSeriesConstants.SOURCE_CODE
}
}
},
{
DateTime.Today.AddMonths(-3), new List<TimeSeries>()
{
new TimeSeries()
{
Quarter = DateTime.Today.AddMonths(-3),
MetricValue = "3",
MetricName = TimeSeriesConstants.TOTAL_COST_CODE
},
new TimeSeries()
{
Quarter = DateTime.Today.AddMonths(-3),
MetricValue = "4",
MetricName = TimeSeriesConstants.TOTAL_VALUE_CODE
},
new TimeSeries()
{
Quarter = DateTime.Today.AddMonths(-3),
MetricValue = "gp",
MetricName =TimeSeriesConstants.SOURCE_CODE
}
}
}
};
}
}
So, assuming I understand your question right, say you have a dictionary like so:
{ Key = "1/1/1900", Value = List Of Objects, of which each has a DateTimeProperty }
...
{ Key = "1/4/1900", Value = List Of Objects, of which each has a DateTimeProperty }
And you are looking to find a set of objects from your dictionary, where it's the latest by time of each key, then you can do this pretty simply with linq:
var latestItems = data.SelectMany(kvp =>
kvp.Value.OrderByDescending(value => value.Quarter).Take(1)
);
This query finds the most recent object in each bucket and then returns that as a single set (not an enumerable of enumerables). You can change the selector inside the SelectMany to find elements in each set as much as you want, as long as you return an IEnumerable from that callback.

Categories

Resources