how to generate randomly football matches in .net c# - c#

as you can see I have ten team in my database, and here's my code, now I want to generate randomly matches in asp.net C#
in this code the problem is that "d" is a list and the return type of Data is object,
the the picture of error is below.
note in database team_id and team_name in relation when you call team id team_name will be show or call.
function is in service and service is calling in controller.
[HttpGet("DoMatch")]
public IActionResult DoMatch()
{
var res= _matchService.DoMatch();
return Ok(res);
}
public ResponseModel DoMatch()
{
var random = new Random();
List<Team> list = _context.Team.ToList();
Dictionary<int, List<Team>> d = new Dictionary<int, List<Team>> { };
var count = list.Count();
for (int i = 0; i < count / 2; i++)
{
List<Team> temp = new List<Team>();
int index1 = random.Next(list.Count);
temp.Add(list[index1]);
list.RemoveAt(index1);
int index2 = random.Next(list.Count);
temp.Add(list[index2]);
list.RemoveAt(index2);
d.Add(i, temp);
}
return new ResponseModel
{
Data = d,
IsSuccess = true
};
}
the error or exception is:
System.NotSupportedException: The collection type 'System.Collections.Generic.Dictionary2[System.Int32,System.Collections.Generic.List1[Fantasy_League.Models.Team]]' on 'FantasyLeague.Models.ViewModels.ResponseModel.Data' is not supported.

The actual problem that you're running into, as described by the exception message you're getting, is that Dictionary<int, ...> cannot be serialized to be sent back in the web response. JSON requires each key to be a string. So you'll need to decide what you actually want your model to look like. Most likely it would work just fine to use the Values from your dictionary.
Data = d.Values,
That will make the JSON data come across as an array where each element is an array with the paired teams in it.
But Fildor makes a good point in his comment, that you could do this more easily by shuffling and pairing up adjacent teams:
Data = list.OrderBy(t => random.Next()).Chunk(2);
Then all that fancy dictionary logic goes away.

Related

Making a list of objects filled with SOAP API data results in "Index out of range" exception

I use an e-commerce SOAP API, forgive me if it's too confusing to answer. I just want to know if I'm just making a stupid mistake before I write a ticket to API maintainers.
public void WriteXML()
{
var results = GetProductsFromApi().results.ToList();
using (var file = File.Create(#"products.xml"))
{
var list = new List<Product>();
var writer = new XmlSerializer(typeof(List<Product>));
foreach (var result in results)
{
var newProduct = new Product
{
Id = result.productId,
Index = result.productDisplayedCode,
Stock = result.productStocksData.productStocksQuantities[0].productSizesData[0].productSizeQuantity,
IsIgnored = false,
IsInDelivery = false
};
list.Add(newProduct);
}
writer.Serialize(file, list);
}
}
I made a request to the API and I want to store it in a list, so each result gets serialized into an XML later. The code above works if I set Stock to something like Stock = 1, - however if left as it is, the program quits with Unhandled exception: System.IndexOutOfRangeException.
What's weird though is that if I do something similar to the following before building the Product object:
Console.WriteLine(result.productStocksData.productStocksQuantities[0].productSizesData[0].productSizeQuantity);
...I am met with a correct API response.
I have no clue what's going on. I tried checking if the result is null before constructing Product, but it didn't help. The whole exception is so confusing to me I don't really know where to start looking.
Edit: Using Fildor's proposed code, I wrote this:
float? lol = result.productStocksData.productStocksQuantities.FirstOrDefault().productSizesData.FirstOrDefault()?.productSizeQuantity ?? null; //doesn't actually change anything if it's null or 0
if (lol.GetValueOrDefault() == 0) {
lol = 1;
};
var newProduct = new Product
{
Id = result.productId,
Index = result.productDisplayedCode,
Stock = (float)lol,
IsIgnored = false,
IsInDelivery = false
};
Console.WriteLine("Processed product has a stock of " + lol);
list.Add(newProduct);
It now results in System.NullReferenceException. It responds with actual stock size, and said error appears after.

How do I store the initial state of a list of objects so that I can compare them to an updated list?

I have a list that is constantly being updated throughout my program. I would like to be able to compare the initial count and final count of my list after every update. The following is just a sample code (the original code is too lengthy) but it sufficiently captures the problem.
class Bot
{
public int ID { get; set; }
}
public class Program
{
public void Main()
{
List<Bot> InitialList = new List<Bot>();
List<Bot> FinalList = new List<Bot>();
for (int i = 0; i < 12345; i++)
{
Bot b = new Bot() {ID = i};
InitialList.Add(b);
}
FinalList = InitialList;
for (int i = 0; i < 12345; i++)
{
Bot b = new Bot() {ID = i};
FinalList.Add(b);
}
Console.Write($"Initial list has {InitialList.Count} bots");
Console.Write($"Final list has {FinalList.Count} bots");
}
}
Output:
Initial list has 24690 bots
Final list has 24690 bots
Expected for both lists to have 12345 bots.
What is correct way to copy the initial list so new set is not simply added to original?
To do what you seem to want to do, you want to copy the list rather than assign a new reference to the same list. So instead of
FinalList = InitialList;
Use
FinalList.AddRange(InitialList);
Basically what you had was two variables both referring to the same list. This way you have two different lists, one with the initial values and one with new values.
That said, you could also just store the count if that's all you want to do.
int initialCount = InitialList.Count;
FinalList = InitialList;
Although there's now no longer a reason to copy from one to the other if you already have the data you need.
I get the feeling you actually want to do more than what's stated in the question though, so the correct approach may change depending on what you actually want to do.

c# class graph to Neo4j

I'm looking to transform my in memory Plain old C# classes into a neo4j database.
(Class types are node types and derive from, nodes have a List for "linkedTo")
Rather than write a long series of cypher queries to create nodes and properties then link them with relationships I am wondering if there is anything more clever I can do.
For example can I serialize them to json and then import that directly into neo4j?
I understand that the .unwind function in the C# neo4j driver may be of help here but do not see good examples of its use and then relationships need to be matched and created separately
Is there an optimal method for doing this? i expect to have around 50k nodes
OK, first off, I'm using Neo4jClient for this and I've added an INDEX to the DB using:
CREATE INDEX ON :MyClass(Id)
This is important for the way this works, as it makes inserting the data a lot quicker.
I have a class:
public class MyClass
{
public int Id {get;set;}
public string AValue {get;set;}
public ICollection<int> LinkToIds {get;set;} = new List<int>();
}
Which has an Id which I'll be keying off, and a string property - just because. The LinkToIds property is a collection of Ids that this instance is linked to.
To generate my MyClass instances I'm using this method to randomly generate them:
private static ICollection<MyClass> GenerateMyClass(int number = 50000){
var output = new List<MyClass>();
Random r = new Random((int) DateTime.Now.Ticks);
for (int i = 0; i < number; i++)
{
var mc = new MyClass { Id = i, AValue = $"Value_{i}" };
var numberOfLinks = r.Next(1, 10);
for(int j = 0; j < numberOfLinks; j++){
var link = r.Next(0, number-1);
if(!mc.LinkToIds.Contains(link) && link != mc.Id)
mc.LinkToIds.Add(link);
}
output.Add(mc);
}
return output;
}
Then I use another method to split this into smaller 'batches':
private static ICollection<ICollection<MyClass>> GetBatches(ICollection<MyClass> toBatch, int sizeOfBatch)
{
var output = new List<ICollection<MyClass>>();
if(sizeOfBatch > toBatch.Count) sizeOfBatch = toBatch.Count;
var numBatches = toBatch.Count / sizeOfBatch;
for(int i = 0; i < numBatches; i++){
output.Add(toBatch.Skip(i * sizeOfBatch).Take(sizeOfBatch).ToList());
}
return output;
}
Then to actually add into the DB:
void Main()
{
var gc = new GraphClient(new Uri("http://localhost:7474/db/data"), "neo4j", "neo");
gc.Connect();
var batches = GetBatches(GenerateMyClass(), 5000);
var now = DateTime.Now;
foreach (var batch in batches)
{
DateTime bstart = DateTime.Now;
var query = gc.Cypher
.Unwind(batch, "node")
.Merge($"(n:{nameof(MyClass)} {{Id: node.Id}})")
.Set("n = node")
.With("n, node")
.Unwind("node.LinkToIds", "linkTo")
.Merge($"(n1:{nameof(MyClass)} {{Id: linkTo}})")
.With("n, n1")
.Merge("(n)-[:LINKED_TO]->(n1)");
query.ExecuteWithoutResults();
Console.WriteLine($"Batch took: {(DateTime.Now - bstart).TotalMilliseconds} ms");
}
Console.WriteLine($"Total took: {(DateTime.Now - now).TotalMilliseconds} ms");
}
On my aging (5-6 years old now) machine it takes about 20s to put 50,000 nodes in and around about 500,000 relationships.
Let's break into that important call to Neo4j above. The key things are as you rightly suggesting UNWIND - here I UNWIND a batch and give each 'row' in that collection the identifier of node. I can then access the properties (node.Id) and use that to MERGE a node. In the first unwind - I always SET the newly created node (n) to be the node so all the properties (in this case just AValue) are set.
So up to the first With we have a new Node created with a MyClass label, and all it's properties set. Now. This does include having an array of LinkToIds which if you were a tidy person - you might want to remove. I'll leave that to yourself.
In the second UNWIND we take advantage of the fact that the LinkToIds property is an Array, and use that to create a 'placeholder' node that will be filled later, then we create a relationship between the n and the n1 placeholder. NB - if we've already created a node with the same id as n1 we'll use that node, and when we get to the same Id during the first UNWIND we'll set all the properties of the placeholder.
It's not the easiest to explain, but in the best things to look at are MERGE and UNWIND in the Neo4j Documentation.

Trying to make DataAccess function pass back a 2d string array with columns and records for UI class to display

There's two parts to my question, How to do it, and if it's good style to do.
TestDataBaseEntities is the DBContext item being passed.
myQuery is the query being excecuted and read
StatusMessage is passed out of the function for the UI to report whether the operation was a success or not.
Records is what I need help figuring out. I need to figure out how to pass each record back to the calling method of ReadMan().
I was thinking that a 2d string array being passed back would benefit me, because I'd have the data read by this DataAccess class, and ready to display in my UserInterface class. But therein lies the problem.
To declare the string[,], I would need to know the size of the string, or implicitly give it dimensions by doing it like this Records[,] = new string[,] { { FirstField, SecondField }, { FirstField, SecondField } ... } and so on, BUT can't, because the first record being read in doesn't give the information needed to tell Records how large its second index is supposed to be, [ , ThisIndex], If i had this working, i'd pass the 2d Records back for the UserInterface class to Display to user.
Why have this Read function? Because I'm supposed to separate EF functions from UI right?
public class DataAccess
{
public bool ReadMan(TestDatabaseEntities dbEntities, IQueryable myQuery, out string StatusMessage, out string[,] Records)
{
string ErrorMessage;
bool bSuccessful;
string[] ThisRecord;
bSuccessful = TryDataBaseAction(dbEntities, out ErrorMessage,
() =>
{
foreach (Man m in myQuery)
{
// was thinking ThisRecord could be temporary storage but doesn't seem to work to my benefit.
ThisRecord = new string[] { m.ManID.ToString(), m.Name };
}
});
if (bSuccessful)
StatusMessage = "Records read successfully";
else
StatusMessage = ErrorMessage;
return bSuccessful;
}
public bool TryDataBaseAction(TestDatabaseEntities MyDBEntities, out string ErrorMessage, Action MyDBAction)
{
UserInterface MyUI = new UserInterface();
try
{
MyDBAction();
ErrorMessage = "No Error";
return true;
}
catch (Exception e)
{
ErrorMessage = e.ToString();
return false;
}
}
}
EDIT: FIXED
public bool ReadMan(TestDatabaseEntities dbEntities, IQueryable myQuery, out string StatusMessage, out string[,] Records)
{
string ErrorMessage;
bool bSuccessful;
string[,] TheseRecords = null;
// hands an Action() to TryDataBase, as indicated by lambda expression in 3rd arguement.
bSuccessful = TryDataBaseAction(dbEntities, out ErrorMessage,
() =>
{
List<Man> men = myQuery.OfType<Man>().ToList();
TheseRecords = new string[men.Count, 2];
// ERROR BELOW: Operator '<' cannot be applied to operands of type 'int' and 'method group'
for (int i = 0; i < men.Count; i++)
{
TheseRecords[i, 0] = men[i].ManID.ToString();
TheseRecords[i, 1] = men[i].Name;
}
});
Records = TheseRecords;
if (bSuccessful)
StatusMessage = "Records read successfully";
else
StatusMessage = ErrorMessage;
return bSuccessful;
}
Does this help?
bSuccessful = TryDataBaseAction(dbEntities, out ErrorMessage,
() =>
{
List<Man> men = myQuery.OfType<Man>().ToList();
Records = new string[men.Count, 2];
for (int i = 0; i < men.Count; i++)
{
Records[i, 0] = men[i].ManID.ToString();
Records[i, 1] = men[i].Name;
}
});
The key thing here is to convert myQuery into a list so that we can get access to its Count property. Once we have that it is then straightforward to create the Records array.
Whether doing so is good style or not is more subjective and really depends on how your application is architected. Generally speaking I have the data access layer charged with merely executing queries and retrieving data - it is left to the user interface to take care of the visual representation.
Applying this approach to your specfic case, it may have been easier if the ReadMan method took a List or some other collection as the out parameter rather than the 2-D array. This way, the calling method has an easy time of creating the desired representation (you know how many items you are dealing with), plus you avoid having user interface details creeping into the data access layer.
You may be doing this already, but the other thing to consider is how your current approach deals with very large amounts of data. We are materializing everything retreived by myQuery, so if you are wanting to implement some form of paging, it will need to manifest itself in myQuery.

Why am I getting index out of bounds error from database

I know what index out of bounds is all about. When I debug I see why as well. basically what is happening is I do a filter on my database to look for records that are potential/pending. I then gather a array of those numbers send them off to another server to check to see if those numbers have been upgraded to a sale. If it has been upgraded to a sale the server responds back with the new Sales Order ID and my old Pending Sales Order ID (SourceID). I then do a for loop on that list to filter it down that specific SourceID and update the SourceID to be the Sales Order ID and change a couple of other values. Problem is is that when I use that filter on the very first one it throws a index out of bounds error. I check the results returned by the filter and it says 0. Which i find kind of strange because I took the sales order number from the list so it should be there. So i dont know what the deal is. Here is the code in question that throws the error. And it doesn't do it all the time. Like I just ran the code this morning and it didn't throw the error. But last night it did before I went home.
filter.RowFilter = string.Format("Stage = '{0}'", Potential.PotentialSale);
if (filter.Count > 0)
{
var Soids = new int[filter.Count];
Console.Write("Searching for Soids - (");
for (int i = 0; i < filter.Count; i++)
{
Console.Write(filter[i][1].ToString() + ",");
Soids[i] = (int)filter[i][1];
}
Console.WriteLine(")");
var pendingRecords = Server.GetSoldRecords(Soids);
var updateRecords = new NameValueCollection();
for (int i = 0; i < pendingRecords.Length; i++)
{
filter.RowFilter = "Soid = " + pendingRecords[i][1];
filter[0].Row["Soid"] = pendingRecords[i][0];
filter[0].Row["SourceId"] = pendingRecords[i][1];
filter[0].Row["Stage"] = Potential.ClosedWon;
var potentialXML = Potential.GetUpdatePotentialXML(filter[0].Row["Soid"].ToString(), filter[0].Row["Stage"].ToString());
updateRecords.Add(filter[0].Row["ZohoID"].ToString(), potentialXML);
}
if i'm counting right line 17 is the error where the error is thrown. pendingRecords is a object[][] array. pendingRecords[i] is the individual records. pendingRecords[i][0] is the new Sales OrderID (SOID) and pendingRecords[i][1] is the old SOID (now the SourceID)
Any help on this one? is it because i'm changing the SOID to the new SOID, and the filter auto updates itself? I just don't know
Well I ended up changing how it worked all together and it actually sorts it a bit nicer now. The code i am about to post has a bunch of hard coded numbers due to the structure of my table that is returned. Sorry about that. I have learned since then to not do that, but i am working on a different project now and will change that when I have to change the program. But here is the solution.
var potentials = Server.GetNewPotentials(); //loads all records from server
for (int i = 0; i < potentials.Length; i++)
{
var filter = AllPotentials.DefaultView;
var result1 = CheckSoidOrSource(potentials[i].Soid, true);
var result2 = CheckSoidOrSource(potentials[i].SourceID,false) ;
//This potential can't be found at all so let's add it to our table
if (result1+result2==0)
{
Logger.WriteLine("Found new record. Adding it to DataTable and sending it to Zoho");
AllPotentials.Add(potentials[i]);
filter.RowFilter = string.Format("Soid = '{0}'", potentials[i].SourceID);
var index = AllPotentials.Rows.IndexOf(filter[0].Row);
ZohoPoster posterInsert = new ZohoPoster(Zoho.Fields.Potentials, Zoho.Calls.insertRecords);
AllPotentials.Rows[index]["ZohoID"] = posterInsert.PostNewPotentialRecord(3, filter[0].Row);
}
//This potential is not found, but has a SourceId that matches a Soid of another record.
if (result1==0 && result2 == 1)
{
Logger.WriteLine("Found a record that needs to be updated on Zoho");
ZohoPoster posterUpdate = new ZohoPoster(Zoho.Fields.Potentials, Zoho.Calls.updateRecords);
filter.RowFilter = string.Format("Soid = '{0}'", potentials[i].SourceID);
var index = AllPotentials.Rows.IndexOf(filter[0].Row);
AllPotentials.Rows[index]["Soid"] = potentials[i].Soid;
AllPotentials.Rows[index]["SourceId"] = potentials[i].SourceID;
AllPotentials.Rows[index]["PotentialStage"] = potentials[i].PotentialStage;
AllPotentials.Rows[index]["UpdateRecord"] = true;
AllPotentials.Rows[index]["Amount"] = potentials[i].Amount;
AllPotentials.Rows[index]["ZohoID"] = posterUpdate.UpdatePotentialRecord(3, filter[0].Row);
}
}
AllPotentials.AcceptChanges();
}
private int CheckSoidOrSource(string Soid, bool checkSource)
{
var filter = AllPotentials.DefaultView;
if (checkSource)
filter.RowFilter = string.Format("Soid = '{0}' OR SourceId = '{1}'",Soid, Soid);
else
filter.RowFilter = string.Format("Soid = '{0}'", Soid);
return filter.Count;
}
basically what is happening is that i noticed something about my data when I filter it this way. The two results would only return the following results (0,0) (0,1) and (1,0) (0,0) means that the record doesn't exist at all in this table so I need to add it. (1,0) means that the Sales Order ID (Soid) matches another Soid in the table so it already exists. Lastly (0,1) means that the Soid doesn't exist in this table but i found a record that has the Soid as it's source...which to me means that the one that had it as a source has been upgraded from a potential to a sale, which in turn means i have to update the record and Zoho. This worked out to much less work for me because now I don't have to search for won and lost records, i only have to search for lost records. less code same results is always a good thing :)

Categories

Resources