Accessing the properties of an IEnumerable - c#

I'm using TweetInvi to grab a bunch of tweets that match a specified hashtag. I do this with the following:
var matchingTweets = Search.SearchTweets(hashtag);
This returns an IEnumerable (named ITweet, interface of Tweet), however I cannot create a List<> of Tweets, because Tweet is a static type.
I made, instead, a list of objects, using:
List<object> matches = matchingTweets.Cast<object>().ToList();
However, although each member of the matchingTweets IEnumerable has a number of properties, I cannot access them using:
long tweetID = matches[i].<property>;
Using matches[i].ToString() returns the tweet content, so how can I effectively cast the results in matchingTweets to a list, and subsequently access the properties of those list members? I would ideally like to avoid using dynamic.

In your example above you were trying to grab the ID from the tweet. ITweet implements ITweetIdentifier which contains the Id property. You can literally just access it by:
var matchingTweets = Search.SearchTweets(hashtag);
//Grab the first 5 tweets from the results.
var firstFiveTweets = matchingTweets.Take(5).ToList();
//if you only want the ids and not the entire object
var firstFiveTweetIds = matchingTweets.Take(5).Select(t => t.Id).ToList();
//Iterate through and do stuff
foreach (var tweet in matchingTweets)
{
//These are just examples of the properties accessible to you...
if(tweet.Favorited)
{
var text = tweet.FullText;
}
if(tweet.RetweetCount > 100)
{
//TODO: Handle popular tweets...
}
}
//Get item at specific index
matchingTweets.ElementAt(index);
I don't know exactly what you want to do with all the info, but since the SearchTweets returns a IEnumerable of ITweets you have access to anything an ITweet has defined.
I highly recommend looking through their wiki. It's pretty well organized and gives you clear examples of some basic tasks.

It makes sense you cannot access the properties. You cast it into object so you can only access the objects properties and methods (that like you said might have been overridden).
It should be fine to just access it like this:
List<ITweet> tweets = matchingTweets.Take(5).ToList();
What you can do is project it to a new object of yours:
var tweets = matchingTweets.Select(item => new {
property1 = item.property1,
property2 = item.property2
})
.Take(5).ToList();
Then you will be able to access what you need. Now, if you need to share this data outside the scope of that function create a DTO object and initialize it instead of the anonymous type.
Depending on the size of the project and amount of effort usually it is in any case a good practice to create a layer of DTO objects when you interact with an external service like this. Then if their models changed you can contain your changes only to the DTOs.
If all you want are the ids of the first 5 then:
var ids = matchingTweets.Take(5).Select(item => item.id).ToList();

Related

How to map Azure Cosmos DB query recordset to C# class object [duplicate]

I'd like to store several different object types in a single Cosmos DB container, as they are all logically grouped and make sense to read together by timestamp to avoid extra HTTP calls.
However, the Cosmos DB client API doesn't seem to provide an easy way of doing the reads with multiple types. The best solution I've found so far is to write your own CosmosSerializer and JsonConverter, but that feels clunky: https://thomaslevesque.com/2019/10/15/handling-type-hierarchies-in-cosmos-db-part-2/
Is there a more graceful way to read items of different types to a shared base class so I can cast them later, or do I have to take the hit?
Thanks!
The way I do this is to create the ItemQueryIterator and FeedResponse objects as dynamic and initially read them untyped so I can inspect a "type" property that tells me what type of object to deserialize into.
In this example I have a single container that contains both my customer data as well as all their sales orders. The code looks like this.
string sql = "SELECT * from c WHERE c.customerId = #customerId";
FeedIterator<dynamic> resultSet = container.GetItemQueryIterator<dynamic>(
new QueryDefinition(sql)
.WithParameter("#customerId", customerId),
requestOptions: new QueryRequestOptions
{
PartitionKey = new PartitionKey(customerId)
});
CustomerV4 customer = new CustomerV4();
List<SalesOrder> orders = new List<SalesOrder>();
while (resultSet.HasMoreResults)
{
//dynamic response. Deserialize into POCO's based upon "type" property
FeedResponse<dynamic> response = await resultSet.ReadNextAsync();
foreach (var item in response)
{
if (item.type == "customer")
{
customer = JsonConvert.DeserializeObject<CustomerV4>(item.ToString());
}
else if (item.type == "salesOrder")
{
orders.Add(JsonConvert.DeserializeObject<SalesOrder>(item.ToString()));
}
}
}
Update:
You do not have to use dynamic types if want to create a "base document" class and then derive from that. Deserialize into the documentBase class, then check the type property check which class to deserialize the payload into.
You can also extend this pattern when you evolve your data models over time with a docVersion property.

Convert IEnumerable<T> to collection of dynamically generated objects

Recently I asked a more general question about getting properties of model through foreign key.
Now I moved a bit further but still have no idea how transform objects on the fly.
What I've got is an IEnumerable collection which I get through repository
regionRaw = unitOfWork.RegionRepository.Get(
keyOrder: q => q.OrderBy(d => d.RegionID),
filter: p => p.FullName.Contains(lastname) || p.ShortName.Contains(lastname),
orderBy: jtSorting,
includeProperties: "District, ISO31662, GOST767Region");
Further I am going to export data from this collection to Excel. So I need a select statement that gets all the fields I need.
dt = regionRaw
.Select(x => new
{
ISO = x.ISO31662.GOSTName,
DistrictName = x.District.ShortName
})
I do not want to enumerate all the fields I need like on the top.
I am able to make a method that recognizes which of the fields have simple values and which have objects referenced through foreign key. And then that method will return a list of properties.
Now I need some way to write something like a foreach inside select. I see something like this:
dt = regionRaw
.Select(x => new
{
foreach (prop in propList)
{
prop.PropertyName = x.GetType()
.GetProperty(prop.TableName)
.GetValue(x, null).GetType()
.GetProperty(prop.PropertyName)
.GetValue(
x.GetType().GetProperty(prop.TableName).GetValue(x, null),
null);
}
}
Where propList is a collection of properties that I get before.
I do totally realize that upper code is more a pseudo-code but I have no idea how to realize this in .NET.
So if you can suggest some solution for this task I will be very grateful. Or maybe you could explain that all this is a bad idea and shouldn't be realized.
You wont be able to create an anonymous type with dynamic properties as anon types are created during compile and your properties are created during execution.
But why do you need strongly typed properties if you're not going to code against them, as you wont know them until someone executes the query?
Expando object may be of use to you?http://msdn.microsoft.com/en-us/library/system.dynamic.expandoobject.aspx

IEnumerable.GroupJoin and Entity Framework objects

(See this question for a little background on this one.)
I need to match up items in a List<T> collection of Entity records with a List<T> collection of objects (the Entity object collection is of type Citation and the other is of type sRecord). There is a 1-to-1 relationship of sorts between the second collection and the first where each of the objects in the second match up to exactly one record in the first (but not necessarily vice versa). They match on a single field called ID in the Citation class and id in the sRecord class. Trying to run through nested loops to match them up quickly became bogged down, so I sought out a means to match up the entire collections once and then iterate through that matched set.
This is how I put together the suggested group join statement:
var draftMatches = draftRecords.GroupJoin(sRecords,
Citation => Citation.ID,
stiRecord => sRecord.id,
(Citations, sRecords) =>
new
{
Citation = Citations,
sRecord = sRecords.Select(sRecord => sRecord)
});
I don't have much confidence that I got it right.
What I need to do with the resulting matched set is compare fields in the sRecord object to fields in the Citation object to determine whether the Citation object needs to be updated. Since I'm working with Entity, I assumed that I needed to preserve the reference to the Citation object when I updated it in a separate method (separated for code reuse purposes), so this is how I'm trying to do that update:
DateTime recordDate = RecordUtilities.ConvertToDate(match.sRecord.FirstOrDefault().modifiedDate);
int comparison = recordDate.CompareTo((DateTime)match.Citation.modifiedDate);
if (comparison > 0)
{
EntityUtilities.MapToCitation(ref match.Citation, match.sRecord.FirstOrDefault());
updatedDraft++;
}
At this point, I'm getting an IntelliSense error on match.Citation in the call to MapToCitation, stating "A property, indexer, or dynamic member access may not be passed as an out or ref parameter."
I need to ensure that the Citation object that gets saved when I do context.Save() is updated from the sRecord object if appropriate. I also need to make sure that I'm saving time with the matching over the previous code. What do I need to change about my code to achieve these goals?
var draftRecordDic = draftRecords.ToDictionary(record => record.ID);
var sRecordsDic = sRecords.ToDictionary(record => record.ID);
var validKeys = sRecordsDic.Keys.Intersect(draftRecordDic.Keys);
foreach(var key in validKeys)
{
var recOriginal = draftRecordDic[key];
var recMo = sRecordsDic[key];
// do your code here.
}
This should work nicely & is simple to understand.

Querying Complex Object using Lambda

I am querying a complex c# object that describes a Shift Roster. This object is populated from a web service and is an object from a third party software supplier.
My task is to build a gridview from data from this third party product. The object is an that contains other objects nested inside most of which are an array of objects.
I am using Lambda Expressions to navigate down the object, but I am struggling to get values out, and I am also wondering whether the expression I am writing could be better. Here is one example where I am trying to get an employee name out:
var employeeDetails = employeeRoster.PathsRosters.SelectMany(a => a.EmployeesRosters);
var empName = employeeDetails.Select(b => b.Resource.Name).ToList();
foreach (string nam in empName)
{
string var = nam;
}
employeeRoster is the object that I get back from the web service and PathRosters is an array. Then I am querying the result again and casting to a List just to get back the employee name.
Is there a better way of doing this? Unfortunately, I cannot serialize to XML as I have been told it has to be done in memory on the object.
Instead of making two calls, you can do the same with one:
var employeeNames = employeeRoster.PathsRosters.SelectMany(a => a.EmployeesRosters)
.Select(b => b.Resource.Name).ToList();
Also, your foreach loop doesn't do anything. I don't see the point in having this.
var empNames = employeeRoster.PathsRosters.SelectMany(a => a.EmployeesRosters)
.Select(b => b.Resource.Name).ToList();

Count objects within dynamic anonymous object (C#)

I have a dynamic object (it's actually json) that I pass into my MVC WebApi controller.
The json object contains multiple lists within an anonymous object that are submitted to the controller from another application via client.PostAsJsonAsync("myapiurl", objectGraph).
What I need to do to validate the object on the MVC side, is to get the count of objects in each list. I can access the lists dynamically via mydynamicobject.mylist and individual items via mydynamicobject.mylist[index] but I can't seem to be able to get a count of mydynamicobject.mylist.
What I've tried so far:
LINQ extension methods - doesn't work on dynamic
Enumerable.Count(mydynamicobject.mylist) - can't infer type
Any other ideas? The count is actually correctly available in the dynamic object's base but obviously not accessible as a property. Help!
This works now:
// This is a MVC/WebApi method
public dynamic Post(dynamic mydynamicobject)
if (((ICollection)mydynamicobject.mylist).Count == 0)
{
// do something
}
The code that sends the dynamic object (different app):
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Accept.Add
(new MediaTypeWithQualityHeaderValue("application/json"));
var objectGraph = new { mylist = new { Id = 1 }, mylist2 = new { Name = "ABC" } };
var r = client.PostAsJsonAsync("api/mycontroller", objectGraph).Result;
If they are arrays, I believe you're looking for their Length property.
mydynamicobject.mylist.Length
Alternatively, I think you might be able to get away with casting mydynamicobject.mylist to an IEnumerable and then hand it to IEnueramble.Count like so:
IEnumerable.Count((IEnumerable)mydynamicobject.mylist);
you could also do as Paolo mentioned:
((ICollection)mydynamicobject.mylist).Count
Although I can't take credit for that one.

Categories

Resources