Unity Firebase Realtime Database - Get index of child in database - c#

I am attempting to retrieve the index of an entry in my database. I can do this by ordering
the data then grabbing all of the data in my database and counting the elements up to the entry that I want to find the index of. However, this is not a viable solution when the database goes online.
I have tried to use StartAt but it returns Season1 and null
databaseReference.Child("Leaderboards").Child("Season1").StartAt("Player0").GetValueAsync().ContinueWith(task =>
{
print(task.Result.Key);
print(task.Result.GetRawJsonValue());
});
I have also tried to use EndAt but it returns all of the data in Season1
databaseReference.Child("Leaderboards").Child("Season1").EndAt("Player0").GetValueAsync().ContinueWith(task =>
{
print(task.Result.Key);
print(task.Result.GetRawJsonValue());
});
I have also added .OrderByValue() after .Child("Season1") which works fine in foreach(DataSnapshot dataSnapshot in task.Result.Children) but without limiting the data received, there is no point.
Perhaps, I need to restructure my database (Which I am fully willing to do as it does not hold actual data yet) but I do not know what format would fit my needs.
The Database being worked on:

From what I have found out through extensive testing, the functions StartAt() and EndAt() for Firebase Realtime Database only search by value and not key.
In my case, all of my values are integers so my StartAt() and EndAt() functions must include an integer value to filter data. Perhaps you can send a JSON string to filter objects but that requires further testing as the documentation is nonexistent
The best solution to find an index while retrieving as little data as possible would be to loop through the database searching for the key.
A few relevant things that I discovered during my testing are:
.OrderByValue() returns items in a low to high (0-100 and maybe a-z) format and cannot be changed
.StartAt(int value) will begin by showing all values starting at the given value passed into the function Inclusive
.EndAt(int value) will stop showing values from the given value passed into the function oddly enough, this is also Inclusive
.LimitToLast(int count) will only retrieve the last count number of elements from the previous query which in my case, is safer to use than combining .StartAt() with .EndAt() as they can return an unknown amount of data
.LimitToLast(100).LimitToLast(5) and .LimitToLast(100).LimitToFirst(5) both return the same 5 last values
There may be some cases when using .EndAt(int value).LimitToLast(int count) does not return all of the elements at value which can prevent a recursive function from progressing. As stacking .LimitToLast().LimitToFirst/Last() only returns the last values you cannot use it to iterate through the elements in the database. In this case, you can use .StartAt(int value).EndAt(int value) to obtain all elements with that value which would unfortunately return up to the entire database. This issue would happen at the start of a season when all scores are 0. A possible workaround for this issue would be to check if the current element is 0 (lowest possible value) and then return the count of higher elements
My example will be ran inside of an IEnumerator instead of .GetValueAsync().ContinueWith(task => { }); since I am updating on screen elements
Rough example:
bool hasData = false;
int index = 0;
//start getting baseData
System.Threading.Tasks.Task<DataSnapshot> getLeaderboardTask = databaseReference.Child(DB_LEADERBOARD).Child(season).OrderByValue().LimitToLast(100).GetValueAsync();
//wait for data to be loaded
while (!getLeaderboardTask.IsCompleted) yield return null;
//Check for player value
foreach (DataSnapshot snap in getLeaderboardTask.Result.Children)
{
if (snap.Key.Equals(playerName))
{
hasData = true;
//Do something with the data - Remember to get index, you should use `((int)getLeaderboardTask.Result.ChildrenCount) - index` because Firebase counts in ascending order
break;
}
index++;
}
//check if we need to iterate deeper
if (!hasData)
{
//get new task
System.Threading.Tasks.Task<DataSnapshot> getLeaderboardTask = databaseReference.Child(DB_LEADERBOARD).Child(season).OrderByValue().EndAt(endAtValue).LimitToLast(100).GetValueAsync();
//continue searching while data hasn't been found
while (!hasData)
{
//Wait for current data
while (!getLeaderboardTask.IsCompleted) yield return null;
#region Check if we have the player ranks yet
//get global Data
if (!hasData)
{
int lastRank = 0;
//loop through the data that we just grabbed to look for the player global rank
foreach (DataSnapshot snap in getLeaderboardTask.Result.Children)
{
if (snap.Key.Equals(playerName))
{
hasData = true;
//Do something with the data - Remember to get index, you should use `((int)getLeaderboardTask.Result.ChildrenCount) - index` because Firebase counts in ascending order
break;
}
lastRank = int.Parse(snap.GetRawJsonValue());
index++;
}
//we did not find the player yet, look for them 1 step deeper
if (!hasData)
{
//we are caught in a loop unable to look deeper, search through all elements at this value
if (endAtValue == lastRank)
{
getLeaderboardTask = databaseReference.Child(DB_LEADERBOARD).Child(season).OrderByValue().StartAt(endAtValue).EndAt(endAtValue).GetValueAsync();
//decriment globalEndAtValue in case we do not find it at the current value
endAtValue--;
}
else
{
endAtValue = lastRank;
//we are not in a loop and can continue searching at lastRank
getLeaderboardTask = databaseReference.Child(DB_LEADERBOARD).Child(season).OrderByValue().EndAt(endAtValue).LimitToLast(100).GetValueAsync();
}
}
}
}
}

Not getting any query reults
In your code you have an uppercase P in Player0, but in the database all keys use a lowercase p like player0. That might explain why your reads are not giving results, as queries in Firebase are case-sensitive.
Getting the index of a node
I can [get the index] by ordering the data then grabbing all of the data in my database and counting the elements up to the entry that I want to find the index of. However, this is not a viable solution when the database goes online.
Unfortunately, counting the nodes before it is the only way to get the index of a node in the Firebase Realtime Database. There is nothing built into the database to get the index of a node, so even if it exposed an API for it - it would essentially be doing the same internally.

Related

C# Recursive Search an array of Objects.parent_id for value, then search those and so on till none left

Looking for a solution to find an object.id and get all the parent_id's in an array of objects, and then set object.missed = true.
Object.id, and Object parent_id. If the object doesn't have a parent_id, parent_id = id.
I know how to do it for one level of parent_id's. How can I go unlimited levels deep? Below is the code I have for searching the 1 level.
public class EPlan
{
public int id;
public int parent_id;
public bool is_repeatable;
public bool missed;
}
EPlan[] plans = Array.FindAll(eventsPlan, item => item.parent_id == event_id);
foreach (EPlan plan in plans)
{
plan.missed = true;
plan.is_repeatable = false;
}
I'm trying to search for event_id an int. So I search all of the object.id's for event_id. Once I find object.id == event_id. I need to set object.is_repeatable = false and object.missed = true.
Then I need to search all of the objects.parent_id for current object.id (event_id). Change all of those object to the same as above.
Then I need to check all of those object.id's against all of the object.parent_id's and do the same to those. Like a tree affect. 1 event was missed, and any of the events that are parented to that event need to be set as missed as well.
So far, all I can do is get 1 level deep, or code multiple foreach loops in. But it could be 10 or more levels deep. So that doesn't make sense.
Any help is appreciated. There has to be a better way that the multiple loops.
I too was confused by the question, save for the one line you said:
1 event was missed, and any of the events that are parented to that event need to be set as missed as well.
With that in mind, I suggest the following code will do what you're looking for. Each time you call the method, it will find all of the objects in the array that match the ID and set the event as Missed and Is_Repeatable appropriately.
It also keeps a running list of the Parent_ID's it found during this scan. Once the loop is finished it will call itself, using the list of parent id values instead of the passed in list of events ids it just used. That is the trick that makes the recursion work here.
To start the process off, you call the method with the single event ID you did for 1-level search.
findEvents(new List<string>{event_id}, eventsPlan);
private void findEvents(List<int> eventIDs, EPlan[] eventsPlan)
{
foreach (int eventID in eventIDs)
{
EPlan[] plans = Array.FindAll(eventsPlan, item => item.parent_id == eventID);
List<int> parentIDs = new List<int>();
foreach (EPlan plan in plans)
{
plan.missed = true;
plan.is_repeatable = false;
parentIDs.Add(plan.parent_id);
}
if (parentIDs.Count > 0)
findEvents(parentIDs, eventsPlan);
}
}
I also recommend that if you have the chance to reengineer this code to not use arrays, but a Generic Collection (like List<EPlan>) you can avoid the performance penalty this code has because it's building new arrays in memory each time you call the Array.FindAll method. Using the Generic Collection, or even using old-school foreach loop will work faster when processing a lot of data here.
Update 1:
To answer your question about how you might go about this using a Generic Collection instead:
private void findEventsAsList(List<int> eventIDs, List<EPlan> eventsPlans)
{
List<int> parentIDs = new List<int>();
foreach (EPlan plan in eventsPlans.Where(p => eventIDs.Contains(p.parent_id)))
{
plan.missed = true;
plan.is_repeatable = false;
parentIDs.Add(plan.parent_id);
}
findEventsAsList(parentIDs, eventsPlan);
}

Create a copy of IEnumerable<T> to modify collection from different threads?

I am using a thread party data model which uses it's custom data model. Hierarchy of the data model is as below:
Model
---Tables(type of Table)
-----Rows(type of Row)
-------Cells( type of Cell)
Table has property Rows as like DataTable and I have to access this property in more than tasks. Now I need a row from the table which has a column value to the specified value.
To do this, I have created a method which has lock statement to make it accessible from only one thread once.
public static Row GetRowWithColumnValue(Model model, string tableKey, string indexColumnKey, string indexColumnValue)
{
Row simObj = null;
lock (syncRoot)
{
SimWrapperFromValueFactory wrapperSimSystem = new SimWrapperFromValueFactory(model, tableKey, indexColumnKey);
simObj = wrapperSimSystem.GetWrapper(indexColumnValue);
}
return simObj;
}
To create the lookup for one of the column in Table, I have create a method which always try to create a copy of the rows to avoid collection modified exception:
Private Function GetTableRows(table As Table) As List(Of Row)
Dim rowsList As New List(Of Row)(table.Rows) 'Case 1
'rowsList.AddRange(table.Rows) 'Case 2
' Case 3
'For i As Integer = 0 To table.Rows.Count - 1
'rowsList.Add(table.Rows.ElementAt(i))
'Next
Return rowsList
End Function
but other threads can modify the table(e.g. add, remove rows or update column value in any rows). I am getting below "Collection modified exception":
at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
at System.Collections.Generic.List`1.Enumerator.MoveNextRare()
at System.Collections.Generic.List`1.InsertRange(Int32 index, IEnumerable`1 collection)
I cannot modify this third party library to concurrent collections and this same Data Model shared between multiple project.
Question: I hunting for the solution that let me allow multiple readers on this collection either it modified in another threads.. Is it possible to Get a copy of the collection without getting exception??
Referenced below SO threads but did not find exact solution:
Lock vs. ToArray for thread safe foreach access of List collection
Can ToArray() throw an exception?
Is returning an IEnumerable<> thread-safe?
The simplest solution is to retry on exception, like this:
private List<Row> CopyVolatileList(IEnumerable<Row> original)
{
while (true)
{
try
{
List<Row> copy = new List<Row>();
foreach (Row row in original) {
copy.Add(row);
}
// Validate.
if (copy.Count != 0 && copy[copy.Count - 1] == null) // Assuming Row is a reference type.
{
// At least one element was removed from the list while were copying.
continue;
}
return copy;
}
catch (InvalidOperationException)
{
// Check ex.Message?
}
// Keep trying.
}
}
Eventually you'll get a run where the exception isn't thrown and the data integrity validation passes.
Alternatively, you can dive deep (and I mean very, very deep).
DISCLAIMER: Never ever use this in production. Unless you're desperate and really have no other option.
So we've established that you're working with a custom collection (TableRowCollection) which ultimately uses List<Row>.Enumerator to iterate through the rows. This strongly suggests that your collection is backed by a List<Row>.
First things first, you need to get a reference to that list. Your collection will not expose it publicly, so you'll need to fiddle a bit. You will need to use Reflection to find and get the value of the backing list. I recommend looking at your TableRowCollection in the debugger. It will show you non-public members and you will know what to reflect.
If you can't find your List<Row>, then take a closer look at TableRowCollection.GetEnumerator() - specifically GetEnumerator().GetType(). If that returns List<Row>.Enumerator, then bingo: we can get the backing list out of it, like so:
List<Row> list;
using (IEnumerator<Row> enumerator = table.GetEnumerator())
{
list = (List<Row>)typeof(List<Row>.Enumerator)
.GetField("list", BindingFlags.Instance | BindingFlags.NonPublic)
.GetValue(enumerator);
}
If the above methods of getting your List<Row> have failed, there is no need to read further. You might as well give up.
In case you've succeeded, now that you have the backing List<Row>, we'll have to look at Reference Source for List<T>.
What we see is 3 fields being used:
private T[] _items;
private int _size; // Accessible via "Count".
private int _version;
Our goal is to copy the items whose indexes are between zero and _size - 1 from the _items array into a new array, and to do so in between _version changes.
Observations re thread safety: List<T> does not use locks, none of the fields are marked as volatile and _version is incremented via ++, not Interlocked.Increment. Long story short this means that it is impossible to read all 3 field values and confidently say that we're looking at stable data. We'll have to read the field values repeatedly in order to be somewhat confident that we're looking at a reasonable snapshot (we will never be 100% confident, but you might choose to settle for "good enough").
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
using System.Threading;
private Row[] CopyVolatileList(List<Row> original)
{
while (true)
{
// Get _items and _size values which are safe to use in tandem.
int version = GetVersion(original); // _version.
Row[] items = GetItems(original); // _items.
int count = original.Count; // _size.
if (items.Length < count)
{
// Definitely a torn read. Copy will fail.
continue;
}
// Copy.
Row[] copy = new Row[count];
Array.Copy(items, 0, copy, 0, count);
// Stabilization window.
Thread.Sleep(1);
// Validate.
if (version == GetVersion(original)) {
return copy;
}
// Keep trying.
}
}
static Func<List<Row>, int> GetVersion = CompilePrivateFieldAccessor<List<Row>, int>("_version");
static Func<List<Row>, Row[]> GetItems = CompilePrivateFieldAccessor<List<Row>, Row[]>("_items");
static Func<TObject, TField> CompilePrivateFieldAccessor<TObject, TField>(string fieldName)
{
ParameterExpression param = Expression.Parameter(typeof(TObject), "o");
MemberExpression fieldAccess = Expression.PropertyOrField(param, fieldName);
return Expression
.Lambda<Func<TObject, TField>>(fieldAccess, param)
.Compile();
}
Note re stabilization window: the bigger it is, the more confidence you have that you're not dealing with a torn read (because the list is in process of modifying all 3 fields). I've settled on the smallest value I couldn't fail in my tests where I called CopyVolatileList in a tight loop on one thread, and used another thread to add items to the list, remove them or clear the list at random intervals between 0 and 20ms.
If you remove the stabilization window, you will occasionally get a copy with uninitialized elements at the end of the array because the other thread has removed a row while you were copying - that's why it's needed.
You should obviously validate the copy once it's built, to the best of your ability (at least check for uninitialized elements at the end of the array in case the stabilization window fails).
Good luck.

Prevent infinite loop between objects referencing each other?

Okay, so I wasn't completely sure what headline would fit my problem, but here goes the description:
I have objects than can reference other objects, to create dropdown lists where the content/values is dependant on what values is chosen in "parent" dropdowns.
My dropdown objects contain an id, and a parentId (and other stuff, not relevant here).
I want to prevent the users from making infinite loops, like this:
List 1 (Dependant on list 3)
List 2 (Dependant on list 1)
List 3 (Dependant on list 2)
I've tried writing a recursive method to prevent it, but I cannot figure out the logic.
Could anyone tell me how you would ensure that an object isn't referencing it self "down the line" ? Or provide an example perhaps.
Any help is much appreciated.
The simplest way I can think of is to create a flattened list. Recursively iterate the objects and store each reference in a list. As you find new objects check each one in the list.
You'll either encounter an object referencing itself or run out of objects to search.
This method being suitable will depend on your requirements, speed / memory/ number of items in the list.
Since all object contain an id the list could store/check that instead if you need to check value equality instead of reference equality
If you have written a recursive function to manage those lists, one solution could be to create a list of elements and pass it as parameter into the recursive function and en each iteration add the current item to the list. To stop the recursive function, only check if the current item has been added previously to the list.
If you iterate through the actual elements of each list by relying on specific counters for each list you shouldn't find any problem. The most likely way to provoke an infinite loop is changing the value of a counter from an external source. Example:
for(int i = 0; i < max_i; i++)
{
if(val1[i] != null)
{
for(int j = 0; j < max_j; j++)
{
if(val2[j] != null)
{
//Delete or anything
//YOU CANNOT AFFECT NEITHER i NOR j DIRECTLY.
}
}
}
If you want to account for varying values of j in the internal part, you should rely on a different variable. Example:
if(val2[j] != null)
{
int j2 = j;
//Do whatever with j2, never with j
}
By doing this (associating different counters to different loops), no endless loop will occur. An endless loop occurs when: i = 1, 2, 3, 4 and suddenly i is changed to 2 by an "external source"; thus solution: NEVER change i other than through the for loop.
Thanks everyone for your input on this. I went with James suggestion using a list and ended up with the following code (which may or may not make sense for anyone else but me)
public static bool BadParent(int fieldId, int childId, List<int> list)
{
if (list == null)
list = new List<int>();
bool returnValue = true;
var field = EkstraFelterBLL.getEkstraFeltUdfraEkstraFeltId(fieldId);
if (field != null)
{
if (field.ParentEkstraFeltId == childId)
returnValue = false; //loop reference, fail
else if (list.Contains(field.EkstraFeltId))
returnValue = false; //already been in the cycle, fail
else
{
list.Add(field.EkstraFeltId);
returnValue = BadParent(field.ParentEkstraFeltId, childId, list);
}
}
return returnValue;
}

How could I determine if an array contains a value at a particular index?

I have an array with values at meaningful indices. How can I tell if a particular there is a value at a particular element?
Array.Exists() is the closest I've found, but it looks overcomplicated for what I want, so I'm curious to know if it's really the best way.
UPDATE
OK, so I have an array of objects:
ImageGroup[] Images;
And the index of the elements corresponds to a feature of that item. In this case, the index refers to a value within the filename of the original image. When I come across a filename, I want to check if an element exists at the corresponding index and create one if not.
So I want to know if Images[someInt] exists.
Updated
With the last update this looks more like a dictionary (unless you're going in numerical order and not where "1,2,5" may have been populated, but 3,4 are absent and need to be created). If this is something where index could potentially skip, I would recommend a dictionary:
Dictionary<Int32,Image> images = new Dictionary<Int32, Image>();
// populated previously
Int32 needle = GetIndexOfImage(newImage);
if (!images.ContainsKey(needle))
images.Add(needle, newImage);
Then, once you're done populating, you can then re-reference the item by index in the following fashion:
images[specificIndex]
Once more, you can retrieve all the elements stored using the following as well:
images.Values
Some resources:
Dictionary
Dictionary.ContainsKey
First response:
if (a[index] == interesting) ....
After the Edit(s):
int index = GetIndexFromFilename(filename);
// if (Images[index] != null && Images[index] == interesting) ....
if (Images[index] == null)
Images[index] = CreateImage(filename);
But you should probably just use a Dictionary<string, Image> and use filename as the Key.
It sounds like what you're looking for is the functionality of a dictionary. It would be extremely helpful if you posted how you're populating your array, and how you want to be able to index it. From what I can gather, this is how I would implement...
Dictionary<SomeEnum, ImageGroup> images = new Dictionary<SomeEnum, ImageGroup>();
foreach(SomeEnum enumValue in Enum.GetValues(typeof(SomeEnum)))
{
ImageGroup group = BuildImageGroup();
images.Add(enumValue, group);
}
then you can do:
...
if(images.ContainsKey(SomeEnum.SomeValue))
return images[SomeEnum.SomeValue];
else
return DoSomethingFancy();
If you have multiple image groups for a single enum value (collisions), then you can use a collection of ImageGroups in the dictionary, like this:
Dictionary<SomeEnum, ImageGroup[]>

System.Guid.NewGuid() in linq select

I wanted to generate a unique identifier for the results of a Linq query i did on some date.
Initially i thought of using Guid for that but stumbling upon this problem i had to improvise.
However I'd like to see if anyone could have a solution using Guid so here we go.
Imagine we have:
class Query
{
public class Entry
{
public string Id { get; set; }
public int Value { get; set; }
}
public static IEnumerable<Entry> GetEntries( IEnumerable<int> list)
{
var result =
from i in list
select new Entry
{
Id = System.Guid.NewGuid().ToString("N"),
Value = i
};
return result;
}
}
Now we want Id to be unique for each entry, but we need this value to be the same for each traversal of the IEnumerable we get from GetEntries. This means that we want calling the following code:
List<int> list = new List<int> { 1, 2, 3, 4, 5 };
IEnumerable<Query.Entry> entries = Query.GetEntries(list);
Console.WriteLine("first pass");
foreach (var e in entries) { Console.WriteLine("{0} {1}", e.Value, e.Id); }
Console.WriteLine("second pass");
foreach (var e in entries) { Console.WriteLine("{0} {1}", e.Value, e.Id); }
to give us something like:
first pass
1 47f4a21a037c4ac98a336903ca9df15b
2 f339409bde22487e921e9063e016b717
3 8f41e0da06d84a58a61226a05e12e519
4 013cddf287da46cc919bab224eae9ee0
5 6df157da4e404b3a8309a55de8a95740
second pass
1 47f4a21a037c4ac98a336903ca9df15b
2 f339409bde22487e921e9063e016b717
3 8f41e0da06d84a58a61226a05e12e519
4 013cddf287da46cc919bab224eae9ee0
5 6df157da4e404b3a8309a55de8a95740
However we get:
first pass
1 47f4a21a037c4ac98a336903ca9df15b
2 f339409bde22487e921e9063e016b717
3 8f41e0da06d84a58a61226a05e12e519
4 013cddf287da46cc919bab224eae9ee0
5 6df157da4e404b3a8309a55de8a95740
second pass
1 a9433568e75f4f209c688962ee4da577
2 2d643f4b58b946ba9d02b7ba81064274
3 2ffbcca569fb450b9a8a38872a9fce5f
4 04000e5dfad340c1887ede0119faa16b
5 73a11e06e087408fbe1909f509f08d03
Now taking a second look at my code above I realized where my error was:
The assignment of Id to Guid.NewGuid().ToString("N") gets called every time we traverse the collection and thus is different everytime.
So what should i do then?
Is there a way i can reassure that i will get with only one copy of the collection everytime?
Is there a way that i'm sure that i won't be getting the new instances of the result of the query?
Thank you for your time in advance :)
This is a inherent to all LINQ queries. Being repeatable is coincidental, not guaranteed.
You can solve it with a .ToList() , like:
IEnumerable<Query.Entry> entries = Query.GetEntries(list).ToList();
Or better, move the .ToList() inside GetEntries()
Perhaps you need to produce the list of entries once, and return the same list each time in GetEntries.
Edit:
Ah no, you get each time the different list! Well, then it depends on what you want to get. If you want to get the same Id for each specific Value, maybe in different lists, you need to cache Ids: you should have a Dictionary<int, Guid> where you'll store the already allocated GUIDs. If you want your GUIDs be unique for each source list, you would perhaps need to cache the input the return IEnumerables, and always check if this input list was already returned or not.
Edit:
If you don't want to share the same GUIDs for different runs of GetEntries, you should just "materialize" the query (replacing return result; with return result.ToList();, for example), as it was suggested in the comment to your question.
Otherwise the query will run each time you traverse your list. This is what is called lazy evaluation. The lazy evaluation is usually not a problem, but in your case it leads to recalculating the GUID each query run (i.e., each loop over the result sequence).
Any reason you have to use LINQ? The following seems to work for me:
public static IEnumerable<Entry> GetEntries(IEnumerable<int> list)
{
List<Entry> results = new List<Entry>();
foreach (int i in list)
{
results.Add(new Entry() { Id = Guid.NewGuid().ToString("N"), Value = i });
}
return results;
}
That's because of the way linq works. When you return just the linq query, it is executed every time you enumerate over it. Therefore, for each list item Guid.NewGuid will be executed as many times as you enumerate over the query.
Try adding an item to the list after you iterated once over the query and you will see, that when iterating a second time, the just added list item will be also in the result set. That's because the linq query holds an instance of your list and not an independent copy.
To get always the same result, return an array or list instead of the linq query, so change the return line of the GetEntries method to something like that:
return result.ToArray();
This forces immediate execution, which also happens only once.
Best Regards,
Oliver Hanappi
You might think not using Guid, at least not with "new".
Using GetHashCode() returns unique values that don't change when you traverse the list multiple times.
The problem is that your list is IEnumerable<int>, so the hash code of each item coincides with its value.
You should re-evaluate your approach and use a different strategy. One thing that comes into my mind is to use a pseudo-random number generator initialized with the hash code of the collection. It will return you always the same numbers as soon as it's initialized with the same value. But, again, forget Guid
One suggestion: (Don't know if that's your case or not though)
If you want to save the entries in database, Try to assign your entry's primary key a Guid at the database level. This way, each entry will have a unique and persisted Guid as its primary key. Checkout this link for more info.

Categories

Resources