Add an anonymous class of object to an anonymous list - c#

I've declare a anonymous list like this, and it contain list of contact also
var ContactGroup = new[] { new { ContactGroupKey = 0, ContactGroupTLK = 0, Desc = "", Contacts=new List<object>() } }.ToList();
I try to check the list, if the ContactGroupKey is exists then update only the Contacts(defined as a list) else insert a new contactgroup. but when i tried to add a new contactgroup inside my anonymous list its throw an error "The best overloaded method match for 'System.Collections.Generic.List.Add(AnonymousType#2)' has some invalid arguments
" I'm using anonymous list first time. I tried to avoid classes in this scenario. can any one suggest me where i made the mistake?
while()
{
var Contact= new {
ContactKey = Convert.ToInt64(DB["ContactKey", "0"]),
FirstName = DB["FirstName", ""].ToString(),
Surname = DB["Surname", ""].ToString(),
FullName = DB["Fullname", ""].ToString(),
Street = DB["bStreet", ""].ToString(),
City = DB["bCity", ""].ToString(),
};
foreach (var item in ContactGroup)
{
if (item.ContactGroupKey == Contact.ClaimContactGroupKey)
{
item.Contacts.Add(Contact);
added = true;
}
}
if(!added){
ContactGroup.Add(new {
ContactGroupKey = Convert.ToInt64(DB["ContactGroupKey", "0"]),
ContactGroupTLK = Convert.ToInt64(DB["TranslationKey", "0"]),
Desc = DB["Description", ""].ToString(),
Contacts=GenerateList(Contact)
});
}
}// End While
public static List<T> GenerateList<T>(T itemOftype)
{
List<T> newList = new List<T>();
return newList;
}

The problem is that the anonymous types you're using aren't the same. You need to get the properties to match in name, type and order. Look at this:
ContactGroup.Add(new {
ContactGroupKey = Convert.ToInt64(DB["ContactGroupKey", "0"]),
ContactGroupTLK = Convert.ToInt64(DB["TranslationKey", "0"]),
Desc = DB["Description", ""].ToString(),
Contacts=GenerateList(Contact)
});
That will have ContractGroupKey and ContactGruopTLK as long properties, and Contacts as a List<T> where T is your other anonymous type. You would need to change your initialization to be something like:
var sampleContact = new { ContactKey = 0L, /* etc */ };
var sampleContactList = new[] { sampleContact }.ToList();
var contactGroup = new[] { new { ContactGroupKey = 0L,
ContactGroupTLK = 0L,
Desc = "",
Contacts = sampleContactList } }.ToList();
That could work - but you'd be better off creating named classes for this. Ultimately it feels like these are likely to be significant entities in your system, so it's worth putting the effort into modelling them as named types to start with.
(Side note: it's worth being consistent in your naming; normally local variables are camelCased, so you should use contactGroup rather than ContactGroup, etc.)

Anonymous types are not intended to leave the current method. You cannot pass them to other methods. You should define a class containing the properties you need to handle.

Related

How can I use begins_with method on sort key using c# in DynamoDB

If I was to use the high level model, I might try something like this:
public async void GetBooksData()
{
GetItemRequest request = new GetItemRequest
{
TableName = "Customer",
Key = new Dictionary<string, AttributeValue>
{
{"UserName", new AttributeValue{S="a"} },
{"BookNum", new AttributeValue { S = starts_with(queryTerm)} }
}
};
try
{
var response = await client.GetItemAsync(request);
if (response.HttpStatusCode == System.Net.HttpStatusCode.OK)
{
if (response.Item.Count > 0)
{
foreach (var item in response.Item)
{
MessageBox.Show("Value : \n" + item.Value.S);
}
}
}
}
catch (InternalServerErrorException iee)
{
MessageBox.Show(iee);
}
}
I need to use the method 'begins_with' for getting 2 items what UserName is 'a' and the BookNum are book_1 and book_2. This is possible in the high level interface in Java. As an example as to what can be done on the range key in Java:
public List<Comment> allForItemWithMinRating(String itemId, int minRating) {
Comment comment = new Comment();
comment.setItemId(itemId);
Condition condition = new Condition()
.withComparisonOperator(ComparisonOperator.GE)
.withAttributeValueList(
new AttributeValue()
.withN(Integer.toString(minRating)));
DynamoDBQueryExpression<Comment> queryExpression
= new DynamoDBQueryExpression<Comment>()
.withHashKeyValues(comment)
.withRangeKeyCondition(
"rating",
condition
)
.withScanIndexForward(false);
return mapper.query(Comment.class, queryExpression);
}
In the low level interface for C# you can achieve this as so:
var requestDynamodb = new QueryRequest
{
TableName = "GroupEdEntries",
KeyConditionExpression = "partition_key = :s_Id and begins_with(sort_key, :sort)",
ExpressionAttributeValues = new Dictionary<string, AttributeValue> {
{":s_Id", new AttributeValue { S = my_id }},
{":sort", new AttributeValue { S = sort_key_starts_with }}
},
ConsistentRead = true
};
var results = await client.QueryAsync(requestDynamodb);
where the keys are called partition_key and sort_key. However, this returns the results as attribute values, which then need to be converted into POCOs one property at a time. It requires using reflection and is made more complicated using converters. It seems strange that this fundamental functionality (as well as other functionality) isn't supported in the C# SDK.
I ended up using reflection to create the tables based on the attributes, when this is also supported by default in Java. Am I missing a high level API for C#?
It's a bit of a different syntax and I can't find it documented anywhere (other than in code comments), but this works for me:
string partition_key = "123";
string sort_key_starts_with = "#type"
List<object> queryVal = new List<object>();
queryVal.Add(sort_key_starts_with);
var myQuery = context.QueryAsync<GroupEdEntry>(partition_key, QueryOperator.BeginsWith, queryVal);
var queryResult = await myQuery.GetRemainingAsync();

Initialise a List with foreach loop of items

I am trying to set the value of object property which is of type List and initialise it by using a foreach to add the items to the list e.g.
var sessionPlanner = new SessionPlannerDTO()
{
Age = "",
NumberOfPlayers = session.numberOfPlayers.Value,
MedicalInformation = "",
PlayerNeeds = "",
SessionDate = session.daySessionDate.Value,
Location = session.Location.locationName,
PracticeView = new List<PracticeViewDTO>(foreach(var practice in session.Sessions){
new PracticeViewDTO(){AbilityLevel = practice.ActivityPlan.abilityLevel.Value,
ActivityUrl = practice.ActivityPlan.activityUrl,
EquipmentNeeds = practice.ActivityPlan.equipmentNeeds,
FacilityNeeds = practice.ActivityPlan.activityNeeds,
HealthAndSafety = practice.ActivityPlan.healthAndSafetyIssues,
SessionTitle = practice.ActivityPlan.activityName
};
})
};
PracticeView is what I am trying to achieve by making it a list without doing the below:
var practiceViewList = new List<PracticeViewDTO>();
foreach(var practice in session.Sessions)
{
var practiceX = new PracticeViewDTO()
{
AbilityLevel = practice.ActivityPlan.abilityLevel.Value,
ActivityUrl = practice.ActivityPlan.activityUrl
};
practiceViewList.Add(practiceX);
}
You can't use other code than assignments in object or collection initializers. So your foreach() there won't compile.
Use session.Sessions.Select() to map the source entities to your DTO, and ToList() to create a list of the result:
sessionPlanner = new SessionPlannerDTO
{
Age = "",
// ...
PracticeView = session.Sessions.Select(s =>
new PracticeViewDTO
{
AbilityLevel = s.ActivityPlan.abilityLevel.Value,
// ...
}).ToList()
};
You also may want to consider using AutoMapper, instead of hand-writing mapping code.

Recursive function issue

I'm working with a tree structure of Installation Places: each one may contain child InstallationPlaces and these can also contain children and so on and so on. I've got the following function:
public JsonResult GetInstPlacesTree()
{
InstallationPlaceModel ipm = new InstallationPlaceModel();
var dataContext = ipm.getRootInstallationPlaces();
var instPlaces = from ip in dataContext.installationPlaces
select new
{
id = ip.installationPlace.id,
Name = ip.installationPlace.mediumDescription,
};
return Json(instPlaces, JsonRequestBehavior.AllowGet);
}
This function returns only the root level of the tree.
I have got two working methods:
one returns the root Installation Places;
the other returns the children of a given Installation Place;
They both return IEnumerable variables.
getRootInstallationPlaces();
getChildInstallationPlaces(id);
How can I achieve to call all the Installation Places and respective children?
I have tried this alternative to the GetInstPlacesTree() function:
private IEnumerable<TreeViewItemModel> GetDefaultInlineData()
{
InstallationPlaceModel ipm = new InstallationPlaceModel();
List<TreeViewItemModel> fullTree = new List<TreeViewItemModel>();
var gipo = ipm.getChildInstallationPlaces(currentInstallationPlace.InstallationPlaceId);
List<TreeViewItemModel> childTree = new List<TreeViewItemModel>();
if (gipo.installationPlaces.Count() > 0)
{
foreach (wsInstallationPlace.installationPlaceOutput child in gipo.installationPlaces)
{
TreeViewItemModel childTreeItem = new TreeViewItemModel
{
Text = child.installationPlace.mediumDescription,
Id = child.installationPlace.id
};
childTree.Add(childTreeItem);
}
}
TreeViewItemModel fatherTreeItem = new TreeViewItemModel
{
Text = currentInstallationPlace.InstallationPlaceMediumDescription,
Id = currentInstallationPlace.InstallationPlaceId,
Items = childTree
};
fullTree.Add(fatherTreeItem);
return fullTree;
}
Any help?
I think something like the following should do what you are after. Essentially it keeps your initial method almost as-is but it populates the child Items of each top-level with a recursive call.
The recursive call grabs the children and adds each child to a List<TreeViewItemModel> to be returned but their children are in turn populated by a call to the recursive function. The recursion will end when there are no children left:
public JsonResult GetInstPlacesTree()
{
InstallationPlaceModel ipm = new InstallationPlaceModel();
var dataContext = ipm.getRootInstallationPlaces();
var instPlaces = from ip in dataContext.installationPlaces
select new TreeViewItemModel
{
id = ip.installationPlace.id,
Name = ip.installationPlace.mediumDescription,
Items = getChildInstallationPlacesRecursive(ip.installationPlace.id, ipm)
};
return Json(instPlaces, JsonRequestBehavior.AllowGet);
}
public List<TreeViewItemModel> getChildInstallationPlacesRecursive(int id, InstallationPlaceModel ipm)
{
List<TreeViewItemModel> children = new List<TreeViewItemModel>();
var gipo = ipm.getChildInstallationPlaces(id);
foreach (wsInstallationPlace.installationPlaceOutput child in gipo.installationPlaces)
{
children.Add(new TreeViewItemModel
{
Text = child.installationPlace.mediumDescription,
Id = child.installationPlace.id,
Items = getChildInstallationPlacesRecursive(child.installationPlace.id, ipm)
});
}
return children;
}
To make it recursive, you have to think that child places are, at the same time, roots of their own childs, then you can call the same function for them.
private IEnumerable<TreeViewItemModel> RecursivePlaces(InstallationPlace root){
var output = new List<TreeViewItemModel>();
output.add(new TreeViewItemModel
{
Text = root.installationPlace.mediumDescription,
Id = root.installationPlace.id
});
foreach(var child in root.installationPlaces)
output.AddRange(RecursivePlaces(child));
return output;
}
//Initial call
RecursivePlaces(ipm.getRootInstallationPlace());
You can solve this without recursion with following approach. I wrote it in some kind of pseudo-code, so you will get an idea what I suggest to accomplish, I didn't used your exact function names and structures and classes...
queue = new List<>();
queue.Add(initialInstallation);
retVal = new List<>();
while (queue.Count > 0) {
retVal.Add(queue[0].GetData());
queue.Add(queue[0].GetChildren());
queue.Remove(0);
}
return retVal;

how to use an Anonymous Type

I have this code:
List<MyObjectOne> myListOne = new List<MyObjectOne>(){new MyObjectOne { ID = 1, field2 = 2}};
List<MyObjectTwo> myListTwo = new List<MyObjectTwo>(){new MyObjectTwo { ID = 4, field6 = "string"}};
bool hasSomething = false;
var result = new[] { new {ID = 0 }}.ToList();
if (hasSomething)
{
// Use list one.
result = myListOne.Select(x => new { ID = x.ID});
}
else
{
// Use list two.
result = myListTwo.Select(x => new { ID = x.ID });
}
foreach (var item in result)
{
// Some logic to manipulate item.ID.
item.ID;
}
What I trying to do it's to use the same anonymous type to select a list of IDs from two different lists. So I use the Select(x => new { ID = x.ID }) in order to create the anonymous type for each table in order to have only one for loop.
The error raised is "Cannot implicitly convert type IEnumerable to List"
¿any idea?
Assuming ID in MyObjectOne and MyObjectTwo are both int's, your code will work if you replace ToList with AsEnumerable:
var result = new[] { new { ID = 0 } }.AsEnumerable();
If the ID properties are some other type (e.g. long's), you need to specify that when creating the anonymous type here:
var result = new[] { new { ID = 0L } }.AsEnumerable();
Or like this:
var result = new[] { new { ID = (long)0 } }.AsEnumerable();
However, this kind of code is kind of confusing, and I wouldn't recommend it for a production environment. Here's an alternative solution that avoids creating a 'dummy' object just for implicit anonymous typing:
var result = hasSomething
? myListOne.Select(x => new { ID = x.ID })
: myListTwo.Select(x => new { ID = x.ID });

Adding properties of an Object together in a collection

I have an app that creates ContactList Objects and adds them to a Dictionary collection. My ContactList objects have a property called AggLabels which is a collection of AggregatedLabel objects containg Name and Count properties. What I am trying to do is change the "else" case of my code snippet so that before adding a new AggregatedLabel it will check whether the AggLabel.Name exists in the AggregatedLabel collection and if this is true it will not add the AggLabel.Name again. Instead it will add the value of AggLabel.Count (type int) to the existing AggregatedLabel object. So for an existing object, if the first Count value was 3 and the second value is 2 then the new Count value should be 5. In simple terms I want to have unique AggLabel Names and add together the Counts where the Names are the same. Hope that makes sense - would appreciate any help. Thanks!
Code snippet
Dictionary<int, ContactList> myContactDictionary = new Dictionary<int, ContactList>();
using (DB2DataReader dr = command.ExecuteReader())
{
while (dr.Read())
{
int id = Convert.ToInt32(dr["CONTACT_LIST_ID"]);
if (!myContactDictionary.ContainsKey(id))
{
ContactList contactList = new ContactList();
contactList.ContactListID = id;
contactList.ContactListName = dr["CONTACT_LIST_NAME"].ToString();
//contactList.AggLabels = new ObservableCollection<AggregatedLabel>() { new AggregatedLabel() { Name = dr["LABEL_NAME"].ToString(), Count = Convert.ToInt32(dr["LABEL_COUNT"])}};
contactList.AggLabels = new ObservableCollection<AggregatedLabel>()
{
new AggregatedLabel()
{
Name = dr["LABEL_NAME"].ToString(),
Count = Convert.ToInt32(dr["LABEL_COUNT"])
}
};
myContactDictionary.Add(id, contactList);
}
else
{
ContactList contactList = myContactDictionary[id];
contactList.AggLabels.Add(
new AggregatedLabel()
{
Name = dr["LABEL_NAME"].ToString(),
Count = Convert.ToInt32(dr["LABEL_COUNT"])
}
);
}
}
}
There are two possible solutions I can think of:
1) Use a dictionary instead of the collection of aggregated labels the same way you do it for the contact dictionary. When yout use the name as key and the count as value, you can use the ContainsKey-Method to check whether the label already exists.
contactList.AggLabels = new Dictionary<string, int>();
...
else
{
ContactList contactList = myContactDictionary[id];
if (contactList.AggLabels.ContainsKey(dr["LABEL_NAME"].ToString()))
{
contactList.AggLabels[dr["LABEL_NAME"].ToString()] += Convert.ToInt32(dr["LABEL_COUNT"]);
}
else
{
contactList.AggLabels.Add(dr["LABEL_NAME"].ToString(), Convert.ToInt32(dr["LABEL_COUNT"]));
}
}
2) I you need to use the AggreagteLabel object you can use a loop to search throug all labels.
else
{
bool flagAggLabelFound = false;
ContactList contactList = myContactDictionary[id];
foreach(AggregateLabel aggLabel in contactList.AggLabels)
{
if(aggLabel.Name == dr["LABEL_NAME"].ToString())
{
aggLabel.Count += Convert.ToInt32(dr["LABEL_COUNT"]);
flagAggLabelFound = true;
break;
}
}
if (!flagAggLabelFound)
{
contactList.AggLabels.Add(
new AggregatedLabel()
{
Name = dr["LABEL_NAME"].ToString(),
Count = Convert.ToInt32(dr["LABEL_COUNT"])
}
);
}
}
I hope this helps.
I would try this:
ContactList contactList = myContactDictionary[id];
AggregateLabel existing = contactList.AggLabels.FirstOrDefault(
l => l.Name == dr["LABEL_NAME"].ToString()
);
if (existing == null) { contactList.AggLabels.Add(
new AggregatedLabel() {
Name = dr["LABEL_NAME"].ToString(),
Count = Convert.ToInt32(dr["LABEL_COUNT"])
}
);
}
else { existing.Count += Convert.ToInt32(dr["LABEL_COUNT"]); }
#extract these Aggregated Labels and put them in a separate Observable collection:
1) If you a Dictionary for storing the labels in the contact list, this should work:
ObservableCollection<AggregateLabel> copyOfAggregateLabels = new ObservableCollection<AggregateLabel>();
foreach (KeyValuePair<string, int> aggLabel in aggregateLabels)
{
copyOfAggregateLabels.Add(
new AggregatedLabel() {
Name = aggLabel.Key,
Count = aggLabel.Value
}
);
}
2) If you use an ObservableCollection of AggregateLabels, you get an AggregateLable instead of a KeyValuePair in the loop. The rest works the same way.
First I thought of something like:
ObservableCollection<AggregateLabel> copyOfAggregateLabels = new ObservableCollection<AggregateLabel>(aggregateLables);
But this way you get a new ObservableCollection, but the labels stored in the new collection are still referring to the same objects as the ones in the collection you copy.

Categories

Resources