Specified Cast Not Valid - XamarinFirebase - c#

This is my firebase database structure
Database Structure
In the child, there are values , Name, Country, Age and Uid. The Uid is the focus in my question.
I am try to fetch the children of the node (Chat) based on the current logged in user.
I am basically trying to do a comparison here that, firebase should get me children who only have the Uid = user.uid. i.e the current logged in user. I thought Equals() could do the trick but i get an error with the cast.
The error points at this line var items = snapshot.Children?.ToEnumerable<DataSnapshot>().Equals(user.uid).ToString;
public void OnDataChange(DataSnapshot snapshot)
{
var items = snapshot.Children?.ToEnumerable<DataSnapshot>().Equals(user.uid).ToString;
var key = snapshot.Key;
HashMap map;
foreach (DataSnapshot item in items)
{
}
Console
my snapshot test: DataSnapshot { key = Chat, value = {-KomfGbZxCGESgyo1PFT={Name=Testing , Ref=7YB3mxMRXxW4lzhbhxi1bx7K4Pf1,
}, -KomcJyR5dCxFucJSB0I={Name=Hi, Ref=K6TEpccn1TbB32T8ThFsYnIl6Wm2, }} }

If you want to filter the user based on Ref attribute, I suggest you make an if-statement inside foreach loop to filter the item:
public void OnDataChange(DataSnapshot snapshot)
{
var items = snapshot.Children?.ToEnumerable<DataSnapshot>();
HashMap map;
foreach (DataSnapshot item in items)
{
//filter the user first
map = (HashMap)item.Value;
string userId = map.Get("Ref")?.ToString();
if (userId!=null&& userId == user.uid)
{
//do what you want to do here.
}
}

When you use ToEnumerable, the type of returned objects is DataSnapshot and it cannot be compared to user.uid. You might want to use linq to grab what you wants. something like:
var items = snapshot.Children?.ToEnumerable(x=> x.uid == user.uid)

Related

Updating List<string> values using linq C#

I have a list of strings that I would like to iterate through and change the values if certain items in the list if they match up to a string value in a separate list of objects.
User inputs an email address into an Event object that contains a list of EventMembers:
List<string> EventMembers
I would then like to check through all users in the database to find the username(e-mail address) that matches with the inputted e-mail address
i understand I cannot change values in a list using a foreach loop, but i'm lost with what to do with linq. Basically i'm trying to do something like this:
var allUsers = _userManager.Users
foreach (var a in allUsers)
{
foreach (var e in #event.EventMembers)
{
if (e == a.UserName)
{
e = a.FirstName + a.LastName;
}
}
}
The best thing would be to define an initial collection of members so you don't keep modifying the list while the foreach is still running. You could then check if EventMembers contain the username and then replace it by accessing the value with the index.
var allUsers = _userManager.Users;
List<string> Members;
foreach (var a in allUsers)
{
if (#event.EventMembers.Contains(a.UserName))
{
var index = #event.Members.IndexOf(a.UserName);
Members[index] = a.FirstName + a.LastName;
}
}
EventMembers = Members;

Use of using statement for Entity Framework DbContext in foreach-loop

There is a parser that parses a text file which contains object definition. The object definitions in the text file have a placeholder handle key. The place holder handle needs to be replaced with actual value by looking up the handle value in DB. In my application I am making use of the Entity framework Core for working with the DB.
The parser returns one object at a time, and I am looking up the handle and other properties in the DB one at a time. This is how the code looks so far:
IEnumerable<ObjectInfo> GetNextContent();
IEnumerable<ObjectInfo> GetNextObjectInfo()
{
foreach (var item in parser.GetNextContent())
{
using (var dbContext = new ContentDbContext())
{
string key = item.Key;
string id = dbContext.Contents.Find(key).ObjectId;
item.Id = id;
// Assign other fields...
yield return item;
}
}
}
The question that I have is that in the code above, the 'using' block is within the foreach loop.
Is this a right thing to do?
The other thought is that I can take the 'using' block outside of the foreach-loop but then I am not sure how would that play out with the iterator in the code.
You should move ContentDbContext into outside for better performance.
This is simply because You just need one context per request.
One DbContext per web request... why?
using (var dbContext = new ContentDbContext())
{
foreach (var item in parser.GetNextContent())
{
string key = item.Key;
string id = dbContext.Contents.Find(key).ObjectId;
item.Id = id;
// Assign other fields...
yield return item;
}
}
Updated
You might also join then make sure that fetch all data at a time
// You need to fetch all `item.Key` from `parser.GetNextContent()` to get all data in `dbContext.Contents`
var keys = parser.GetNextContent().Select(p => p.Key).ToArray();
var result = (from content in dbContext.Contents
join key in keys on content.Id equals key
select new
{
Id = content.ObjectId,
//....
}
If you are use C# 8, using statement may be as below:
using var dbContext = new ContentDbContext();
foreach (var item in parser.GetNextContent())
{
string key = item.Key;
string id = dbContext.Contents.Find(key).ObjectId;
item.Id = id;
// Assign other fields...
yield return item;
}

How to return from Recursive Foreach Function

I am implementing recursion in one of my requirements. My actual requirement is as below:-
There is one master Table called Inventory which has many records like say "Inventory A","Inventory B","Inventory C".
There is one more table called Inventory Bundle which link one Inventory with other. So Inventory Bundle table has two columns :- SI & TI which represent Source Inventory Id and Target Inventory ID.
Record Ex.
SI TI
A B
B C
In my requirement if I click on any inventory then the associated inventory should also be fetched out.
Like here if I click on B then A & C should be fetched out. I use following recursion method to get the requirement:-
List<Guid> vmAllBundle = new List<Guid>();
List<Guid> vmRecursiveBundle = new List<Guid>();
List<Guid> processedList = new List<Guid>();
public List<Guid> GetAllRecursiveBundle(Guid invId, Guid originalInvId)
{
List<Guid> vmInvSrcBundleList = GetSourceInventory(invId); //Fetch to get All Related Source Inventories
List<Guid> vmInvTarBundleList = GetTargetInventory(invId); //Fetch to get All Related Target Inventories
vmAllBundle.AddRange(vmInvSrcBundleList);
vmAllBundle.AddRange(vmInvTarBundleList);
if (vmAllBundle.Contains(originalInvId))
vmAllBundle.Remove(originalInvId);
vmAllBundle = vmAllBundle.Distinct().ToList();
vmRecursiveBundle = vmAllBundle.ToList().Except(processedList).ToList();
foreach (Guid vmInvBundle in vmRecursiveBundle)
{
vmRecursiveBundle.Remove(vmInvBundle);
processedList.Add(vmInvBundle);
GetAllRecursiveBundle(vmInvBundle, originalInvId);
if (vmRecursiveBundle.Count == 0)
return vmAllBundle;
}
return null;
}
I am able to fetch the data using this method but I am facing problem while returning.
When I am returning it is calling GetAllRecursiveBundle() withing the foreach loop and continue to call until all the items in vmAllBundle gets finished. After this it exits the recursion.
This is something new to me so posting the question to ask if this is normal behavior or some code logic has to be changed.
Modified Code
public List<Guid> GetAllRecursiveBundle(Guid invId, Guid originalInvId)
{
if (vmRecursiveBundle.Count > 0)
vmRecursiveBundle.Remove(invId);
List<Guid> vmInvSrcBundleList = GetSourceInventory(invId); //Fetch to get All Related Source Inventories
List<Guid> vmInvTarBundleList = GetTargetInventory(invId); //Fetch to get All Related Target Inventories
vmAllBundle.AddRange(vmInvSrcBundleList);
vmAllBundle.AddRange(vmInvTarBundleList);
if (vmAllBundle.Contains(originalInvId))
vmAllBundle.Remove(originalInvId);
vmAllBundle = vmAllBundle.Distinct().ToList();
vmRecursiveBundle = vmAllBundle.ToList().Except(processedList).ToList();
foreach (Guid vmInvBundle in vmRecursiveBundle)
{
processedList.Add(vmInvBundle);
GetAllRecursiveBundle(vmInvBundle, originalInvId);
if (vmRecursiveBundle.Count == 0)
break;
}
return vmAllBundle;
}
I am very surprised that your code runs at all.
You are modifying the list being iterated by a foreach - normally that would throw an exception.
foreach (Guid vmInvBundle in vmRecursiveBundle)
{
vmRecursiveBundle.Remove(vmInvBundle); // **CRASHES HERE**
}
Modifying the collection being iterated by the foreach is not allowed, and would be considered bad practice even if it were allowed (because it frequently causes bugs).
You could change to a for loop, which has no such scruples:
for (int i = 0; i < vmRecursiveBundle.Count; i++)
{
Guid vmInvBundle = vmRecursiveBundle[i];
vmRecursiveBundle.Remove(vmInvBundle); // **NO CRASH**
i--; // counteracts the i++ so the next Guid is not skipped
}
For further details, see What is the best way to modify a list in a 'foreach' loop?
Normally, recursive method calls need something like a break value, that has to be checked on return, to signal the end of the recursive calls and to stop calling the reursive method. I do not fully understand your code, therefore here is an example:
private string SearchFileRecursive(string directory, string fileToFind)
{
string filePath = null;
string[] files = Directory.GetFiles(directory);
string foundFile = files.FirstOrDefault( file => (0 == string.Compare(Path.GetFileName(file), fileToFind, true)));
if(string.IsNullOrEmpty(foundFile))
{ // not found
string[] subDirectories = Directory.GetDirectories(directory);
foreach(string subDirectory in subDirectories)
{
filePath = SearchFileRecursive(subDirectory, fileToFind);
if(!string.IsNullOrEmpty(filePath)) // found
break;
}
}
else
{ // found
filePath = Path.Combine(directory, foundFile);
}
return filePath;
}

how should I give the user a selection and grab the guid from that selection

I have to give the user an option to select from a list of items and then, pending on what single item they select, I need to get the guid from that item. This will be populated from a Linq query from a Sql table.
I started with this:
private void PopulateGatewayList()
{
var gateways = from gw in _entities.Gateways
where gw.IsActive
select gw;
foreach (var gateway in gateways)
{
checkedListBox_Gateways.Items.Add(gateway.Name);
}
}
But I have no way of grabbing the guid once they check something.
What is a good way of giving the user the name but give me back the guid?
** ANSWER **
Using Michael Yoon's help, I did the following:
private void PopulateGatewayList()
{
var gateways = from gw in _entities.Gateways
where gw.IsActive
select gw;
foreach (var gateway in gateways)
{
checkedListBox_Gateways.Items.Add(new ListItem(gateway.Name, gateway.GatewayId.ToString()));
//checkedListBox_Gateways.Items.Add(gateway.Name);
}
}
private void checkedListBox_Gateways_SelectedIndexChanged(object sender, EventArgs e)
{
foreach (Object selecteditem in checkedListBox_Gateways.SelectedItems)
{
var strItem = selecteditem as ListItem;
Console.WriteLine("Selected: " + strItem.Value);
}
}
You need to add an object to the collection that contains the id and string. You can use KeyValuePair or make your own. I'll use keyvaluepair in my example.
checkedListBox_Gateways.DisplayMember = "Key";
checkedListBox_Gateways.ValueMember = "Value";
checkedListBox_Gateways.Items.Add(new KeyValuePair<string, string>(gateway.Name, gateway.Id.ToString()));
Then you can enumerate the SelectedItems collection, cast each back to a keyvaluepair and get the value out of it.

How do I test for a lookup list item, and add it if it is missing, in SharePoint 2007 via C#?

Hi and thanks for looking!
Background
I am having trouble when I attempt to add a value to a lookup column.
I am using SharePoint 2007 and the app has to run in .NET 2.0. The language is C#. Some lookup columns will allow multiple values.
Question
Using C#, how do I do #'s 2-4 of the following:
Attempt to add a list item to a SP list.
For any lookup columns, check the SP List they are referencing to see if that list contains the value I am attempting to add.
If the value DOES NOT exist in the lookup list, add it.
Associate the newly added lookup value to the list item I was originally trying to add.
I have been googling this, of course, but am still stuck. Here is some code from Microsoft which is a start, but it is still not getting me going (not commented and not intuitive to me):
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
using (SPSite site = new SPSite("http://localhost"))
{
using (SPWeb web = site.RootWeb)
{
SPList customerList = web.Lists.TryGetList("Contoso Customers");
SPList orderList = web.Lists.TryGetList("Contoso Orders");
if (customerList != null && orderList != null)
{
SPListItemCollection customers = customerList.Items;
SPListItemCollection orders = orderList.Items;
string fieldName = "CustIDLookup";
if (!orderList.Fields.ContainsField(fieldName))
return;
SPField lookupFld = orderList.Fields.GetField(fieldName);
foreach (SPListItem customer in customers)
{
SPListItem order = orders.Add();
order[SPBuiltInFieldId.Title] = "Thank you!";
order.Update();
SPFieldLookupValue value = new SPFieldLookupValue(customer.ID, customer.ID.ToString());
order[lookupFld.Id] = value.ToString();
order.Update();
}
}
}
}
}
}
}
Even with Microsoft's examples, I can't get any real traction in figuring out how to actually do this.
Your help is GREATLY appreciated.
//untested pseudocode - hope this points you in the right direction
SPList lookupItems = ... // add code here
SPList list = ... // add code here
string lookupFieldName = "LookupValue"; // change to the appropriate value
foreach(SPListItem item in list.Items)
{
string value = (string)item[lookupFieldName];
if(value.Contains("#")) // value containing hash is most likely a lookup value already
{
// use SPFieldLookupValue to get actual value
SPFieldLookupValue currentValue = new SPFieldLookupValue(value);
value = currentValue.LookupValue;
}
// Get the list item (you will need this to find out its id value)
SPListItem lookupItem = GetLookupListItem(lookupList, value);
if(lookupItem == null)
{
//If it doesn't exist, create it
lookupItem = AddNewLookupItem(lookupList, value);
SPFieldLookupValue lookupValue = new SPFieldLookupValue(lookupItem.ID,value));
item["LookupValue"] = lookupValue.ToString();
item.Update();
}
}
SPListItem GetLookupListItem(SPList lookupList, string value)
{
// iterate through list to find item
// use a list query if the list is too big for this to perform well (see here: http://msdn.microsoft.com/en-us/library/ie/ms456030.aspx)
foreach(SPListItem item in lookupList)
{
string itemValue = (string)item[0]; // assuming lookup list has one field of type string containing lookup value
if(value == itemValue)
{
return item;
}
}
return null;
}
SPListItem AddLookupListItem(SPList list, string value)
{
SPListItem newItem = list.Add();
newItem[0] = value;// assuming lookup list has one field of type string containing lookup value
newItem.Update();
}

Categories