Add Multiple record using Linq-to-SQL - c#

I want to add Multiple rows into Table using Linq to SQL
public static FeedbackDatabaseDataContext context = new FeedbackDatabaseDataContext();
public static bool Insert_Question_Answer(List<QuestionClass.Tabelfields> AllList)
{
Feedback f = new Feedback();
List<Feedback> fadd = new List<Feedback>();
for (int i = 0; i < AllList.Count; i++)
{
f.Email = AllList[i].Email;
f.QuestionID = AllList[i].QuestionID;
f.Answer = AllList[i].SelectedOption;
fadd.Add(f);
}
context.Feedbacks.InsertAllOnSubmit(fadd);
context.SubmitChanges();
return true;
}
When I add records into list object i.e. fadd the record is overwrites with last value of AllList

I'm late to the party, but I thought you might want to know that the for-loop is unnecessary. Better use foreach (you don't need the index).
It gets even more interesting when you use LINQ (renamed method for clarity):
public static void InsertFeedbacks(IEnumerable<QuestionClass.Tabelfields> allList)
{
var fadd = from field in allList
select new Feedback
{
Email = field.Email,
QuestionID = field.QuestionID,
Answer = field.SelectedOption
};
context.Feedbacks.InsertAllOnSubmit(fadd);
context.SubmitChanges();
}
By the way, you shouldn't keep one data context that you access all the time; it's better to create one locally, inside a using statement, that will properly handle the database disconnection.

You should create object of Feedback in the scope of for loop, so change your method to :
public static bool Insert_Question_Answer(List<QuestionClass.Tabelfields> AllList)
{
List<Feedback> fadd = new List<Feedback>();
for (int i = 0; i < AllList.Count; i++)
{
Feedback f = new Feedback();
f.Email = AllList[i].Email;
f.QuestionID = AllList[i].QuestionID;
f.Answer = AllList[i].SelectedOption;
fadd.Add(f);
}
context.Feedbacks.InsertAllOnSubmit(fadd);
context.SubmitChanges();
return true;
}

Related

How can I access multi-element List data stored in a public class?

My first question on SO:
I created this public class, so that I can store three elements in a list:
public class myMultiElementList
{
public string Role {get;set;}
public string Country {get;set;}
public int Commonality {get;set;}
}
In my main class, I then created a new list using this process:
var EmployeeRolesCountry = new List<myMultiElementList>();
var rc1 = new myMultiElementList();
rc1.Role = token.Trim();
rc1.Country = country.Trim();
rc1.Commonality = 1;
EmployeeRolesCountry.Add(rc1);
I've added data to EmployeeRolesCountry and have validated that has 472 lines. However, when I try to retrieve it as below, my ForEach loop only retrieves the final line added to the list, 472 times...
foreach (myMultiElementList tmpClass in EmployeeRolesCountry)
{
string d1Value = tmpClass.Role;
Console.WriteLine(d1Value);
string d2Value = tmpClass.Role;
Console.WriteLine(d2Value);
int d3Value = tmpClass.Commonality;
Console.WriteLine(d3Value);
}
This was the most promising of the potential solutions I found on here, so any pointers greatly appreciated.
EDIT: adding data to EmployeeRolesCountry
/*
Before this starts, data is taken in via a csvReader function and parsed
All of the process below is concerned with two fields in the csv
One is simply the Country. No processing necessary
The other is bio, and this itself needs to be parsed and cleansed several times to take roles out
To keep things making sense, I've taken much of the cleansing out
*/
private void File_upload_Click(object sender, EventArgs e)
{
int pos = 0;
var EmployeeRolesCountry = new List<myMultiElementList>();
var rc1 = new myMultiElementList();
int a = 0;
delimiter = ".";
string token;
foreach (var line in records.Take(100))
{
var fields = line.ToList();
string bio = fields[5];
string country = fields[4];
int role_count = Regex.Matches(bio, delimiter).Count;
a = bio.Length;
for (var i = 0; i < role_count; i++)
{
//here I take first role, by parsing on delimiter, then push back EmployeeRolesCountry with result
pos = bio.IndexOf('.');
if (pos != -1)
{
token = bio.Substring(0, pos);
string original_token = token;
rc1.Role = token.Trim();
rc1.Country = country.Trim();
rc1.Commonality = 1;
EmployeeRolesCountry.Add(rc1);
a = original_token.Length;
bio = bio.Remove(0, a + 1);
}
}
}
}
EDIT:
When grouped by multiple properties, this is how we iterate through the grouped items:
var employeesGroupedByRolwAndCountry = EmployeeRolesCountry.GroupBy(x => new { x.Role, x.Country });
employeesGroupedByRolwAndCountry.ToList().ForEach
(
(countryAndRole) =>
{
Console.WriteLine("Group {0}/{1}", countryAndRole.Key.Country, countryAndRole.Key.Role);
countryAndRole.ToList().ForEach
(
(multiElement) => Console.WriteLine(" : {0}", multiElement.Commonality)
);
}
);
__ ORIGINAL POST __
You are instantiating rc1 only once (outside the loop) and add the same instance to the list.
Please make sure that you do
var rc1 = new myMultiElementList();
inside the loop where you are adding the elements, and not outside.
All references are the same in your case:
var obj = new myObj();
for(i = 0; i < 5; i++)
{
obj.Prop1 = "Prop" + i;
list.Add(obj);
}
now the list has 5 elements, all pointing to the obj (the same instance, the same object in memory), and when you do
obj.Prop1 = "Prop" + 5
you update the same memory address, and all the pointers in the list points to the same instance so, you are not getting 472 copies of the LAST item, but getting the same instance 472 times.
The solution is simple. Create a new instance every time you add to your list:
for(i = 0; i < 5; i++)
{
var obj = new myObj();
obj.Prop1 = "Prop" + i;
list.Add(obj);
}
Hope this helps.

Compare list data with static string in C#

I have the following list,
String UpDownStatus = "UP";
List<db1> StockData = new List<db1>();
db1 newStock = new db1();
newStock.Date = (DateTime)reader["Date"];
newStock.High = (double)reader["High"];
newStock.Low = (double)reader["Low"];
newStock.Close = (double)reader["Close"];
newStock.Up_Down = (string)reader["Up_Down"];
StockData.Add(newStock);
The Up_Down column in my DB has the following two string : "UP" and "DOWN"
how can i compare whether the current value of
for (int i = 0; i < StockData.Count; i++)
{
if(StockData[i].Up_Down.CompareTo(UpDownStatus) != 0)
{
//do something
}
}
I know, i could reframe this statement like if (StockData[i].Up_Down=="UP") but i need a solution where I could use .CompareTo function.
If I understood your question right and you want to do something on all items which have the same up/down-status as the variable UpDownStatus, this would be the easiest way to do it:
foreach (var item in StockData.Where(e => e.Up_Down == UpDownStatus))
{
// do something
}

how to stop looping in file in c#?

I'm Trying to save a customer in file but when i'm saving it, it keeps looping the person i entered i do not know where i'm doing it wrong .The problem is i'm thinking my logic is good but i know i'm doing something wrong somewhere which i can not find it .If you could help me i really appreciate it.
public partial class admin : Window
{
accounts acclist = new accounts();
customers cuslist = new customers();
public admin(string pin, accounts myacc, customers mycus)
{
InitializeComponent();
acclist = myacc;
cuslist = mycus;
}
public void saveaccount()
{
using (StreamWriter writer = new StreamWriter("account.txt"))
{
for (int i = 0; i < acclist.Count; i++)
{
var info = new List<string>
{
acclist[i].accounttype.ToString(),
acclist[i].PIN,
acclist[i].accountnumber,
acclist[i].accountbalance.ToString()
};
var account = String.Join(";", info);
writer.WriteLine(account);
}
}
}
//save to customer file
public void savefile()
{
using (StreamWriter writer = new StreamWriter("customer.txt"))
{
for (int i = 0; i < cuslist.Count; i++)
{
var info = new List<string>
{
cuslist[i].NAME.ToString(),
cuslist[i].pin,
};
var customer = String.Join(";", info);
writer.WriteLine(customer);
}
}
}
// add user
private void Sub_Click(object sender, RoutedEventArgs e)
{
customer newCus = new customer();
account newAcc= new account();
try
{
newCus.NAME = Nameadd.Text;
newCus.pin = pinadd.Text;
newAcc.PIN = pinadd.Text;
newAcc.accountnumber = Accountnumadd.Text;
newAcc.accounttype = 'C';
for (int i = 0; i < acclist.Count; i++)
{
{
if(newAcc.accounttype == 'C')
{
newAcc.PIN = pinadd.Text;
newAcc.accountnumber = Accountnumadd.Text;
newAcc.accounttype = 'S';
}
}
cuslist.add(newCus);
acclist.add(newAcc);
savefile();
saveaccount();
}
}
catch(Exception error)
{
MessageBox.Show(error.Message);
}
}
}
In your "save" event, your doing a for loop over the "count" of elements in your account list. That account list variable is global in scope to your class. The problem is that in your loop, you're adding to that list... so really the list you're iterating over is mutating right under-neath you. As you add that customer, the loop starts next iteration, checks the "count", and ends only when "i" is equal in value to the count. However each pass you're adding to the count... so technically you'll never reach the end as the accList.Count is constantly increasing by 1 each pass.
private void Sub_Click(object sender, RoutedEventArgs e)
{
customer newCus = new customer();
account newAcc= new account();
try
{
newCus.NAME = Nameadd.Text;
newCus.pin = pinadd.Text;
newAcc.PIN = pinadd.Text;
newAcc.accountnumber = Accountnumadd.Text;
newAcc.accounttype = 'C';
for (int i = 0; i < acclist.Count; i++) // here you are checking acclist.Count... each iteration this increases by 1, thus i will never technically ever be equivalent to acclist.Count
{
{
if(newAcc.accounttype == 'C')
{
newAcc.PIN = pinadd.Text;
newAcc.accountnumber = Accountnumadd.Text;
newAcc.accounttype = 'S';
}
}
cuslist.add(newCus);
acclist.add(newAcc); // <-- this is where you're adding to acclist each time. However inside this loop you're constantly increasing its size... thus your infinite loop you're hitting.
savefile();
saveaccount();
}
}
catch(Exception error)
{
MessageBox.Show(error.Message);
}
}
I suggest for one, you use a ForEach statement as it's been suggested. Also, use a separate list to hold your "new" accounts. If you need to add to acclist for whatever reason, then after you've added to your new list, iterate over that and add each one of those back to your acclist. This way you avoid mutating the very object you're looping over.
Another way is to first store the "count" into a variable and check against that so it never changes.
var myCounter = acclist.Count
for (int i = 0; i < myCounter ; i++)
{
...
But, I don't know which option is best for you as I obviously don't know the larger context of what it is you need to ultimately do. :) Either solution should stop your infinite loop though.
Consider the use of a foreach loop. This loop is best used for applications like the one in your savefile() method. It's great for applications where you want to perform an action for every item in a list or collection.
See here: https://msdn.microsoft.com/en-us/library/ttw7t8t6.aspx?f=255&MSPPError=-2147217396
EDIT: The requested example:
List<string> FruitBasket = new List<string>();
FruitBasket.Add("apple");
FruitBasket.Add("banana");
FruitBasket.Add("orange");
foreach (string fruit in FruitBasket)
{
Console.WriteLine(fruit);
}
and this results in an output of:
apple, banana, orange.
In the foreach loop you need to declare a variable of the same type as your collection (so in this example I had a List of strings so I made my variable a string, and then they keyword in assigns this variable to each item in that collection, one at a time, starting from the beginning.

Waiting for a parse.com async task to finish in Unity3D

As part of my school project I'm trying to link two tables to decrease the amount of data stored in one table so I wanted to link my "Scores" class with my "CorrectAnswers" class via the ObjectID. However since the tasks are asynchronous, by the time one task is done saving, the other task has already begun or also finished saving and so the ObjectID returns as null.
Here's the code I'm using:
public void SaveScore()
{
ParseObject SendScore = new ParseObject("Scores");
SendScore["Score"] = CheckAnswer.score;
SendScore["user"] = ParseObject.CreateWithoutData("_User", ParseUser.CurrentUser.ObjectId);
SendScore["TestMode"] = MainMenu.testmode;
SendScore["TotalQuestions"] = QuestionCreation.TotalQuestions;
SendScore["CorrectQuestions"] = CheckAnswer.CorrectQuestions;
SendScore.SaveAsync().ContinueWith(t =>
{
ScoreObjectId = SendScore.ObjectId;
});
ParseObject SendCorrectTopics = new ParseObject("CorrectAnswers");
SendCorrectTopics["Score"] = SendScore.ObjectId;
for (int i = 0; i <= 9; i++)
{
string Topic = "Topic" + (i + 1).ToString();
SendCorrectTopics[Topic] = CheckAnswer.CorrectTopics[i];
}
SendCorrectTopics.SaveAsync();
SceneManager.LoadScene(0);
}
How would I be able to make the second save hold until the first save has finished? I'm somewhat new to C# and so don't quite know all it's features yet. I've looked into "await" but unity doesn't seem to like that. Any help would be greatly appreciated!
Thanks in advance,
EDIT: Okay, after a bit more reading on Unity's coroutines, I found a much better way of checking that only relies on checking when needed:
IEnumerator CheckSave()
{
while(ScoreObjectId == null & !DoneSave))
{
print("Running");
yield return new WaitForSeconds(0.5f);
}
DoneSave = false;
SaveTotalTopics();
}
This seems like a much better way of doing it.
Well, it seems the answer was something I've already done before, even if it is a little ugly.
Using Unity's update function I created a check to make sure the ObjectID is not null and the previous save had completed, as so:
void Update () {
if (ScoreObjectId != null & DoneSave)
{
DoneSave = false;
SaveTotalTopics();
}
Thus splitting it into two saves and creating:
public void SaveScore()
{
ParseObject SendScore = new ParseObject("Scores");
SendScore["Score"] = CheckAnswer.score;
SendScore["user"] = ParseObject.CreateWithoutData("_User", ParseUser.CurrentUser.ObjectId);
SendScore["TestMode"] = MainMenu.testmode;
SendScore["TotalQuestions"] = QuestionCreation.TotalQuestions;
SendScore["CorrectQuestions"] = CheckAnswer.CorrectQuestions;
Task SendingScores = SendScore.SaveAsync().ContinueWith(t =>
{
if (t.IsFaulted || t.IsCanceled)
{
DoneSave = false;
print(t.Exception);
}
else
{
DoneSave = true;
print("Setting object ID!");
ScoreObjectId = SendScore.ObjectId;
print(ScoreObjectId);
}
});
}
void SaveTotalTopics()
{
for (int i = 0; i <= 9; i++)
{
string Topic = "Topic" + (i + 1).ToString();
SendCorrectTopics[Topic] = CheckAnswer.CorrectTopics[i];
}
SendCorrectTopics["UserScore"] = ParseObject.CreateWithoutData("Scores", ScoreObjectId);
SendCorrectTopics.SaveAsync().ContinueWith(t =>
{
if(t.IsFaulted || t.IsCanceled)
{
print(t.Exception);
}
else
{
print("Saved!");
}
});
}
I'd also forgotten to use ParseObject.CreateWithoutData() so my first code snippet wouldn't have worked even if I'd found a better method...
So, although I'm not happy with the final result, at least it works and I don't think running an if statement every frame should significantly impact on my game's performance.
Why not use a bool and a while loop?
public IEnumerator SaveScore()
{
bool canContinue = false;
ParseObject SendScore = new ParseObject("Scores");
SendScore["Score"] = CheckAnswer.score;
SendScore["user"] = ParseObject.CreateWithoutData("_User", ParseUser.CurrentUser.ObjectId);
SendScore["TestMode"] = MainMenu.testmode;
SendScore["TotalQuestions"] = QuestionCreation.TotalQuestions;
SendScore["CorrectQuestions"] = CheckAnswer.CorrectQuestions;
SendScore.SaveAsync().ContinueWith(t =>
{
ScoreObjectId = SendScore.ObjectId;
//set the bool canContinue to true because the first portion of code has finished running
canContinue = true;
});
//wait while the canContinue bool is false
while(!canContinue){
yield return null;
}
//continue your parse code
ParseObject SendCorrectTopics = new ParseObject("CorrectAnswers");
SendCorrectTopics["Score"] = SendScore.ObjectId;
for (int i = 0; i <= 9; i++)
{
string Topic = "Topic" + (i + 1).ToString();
SendCorrectTopics[Topic] = CheckAnswer.CorrectTopics[i];
}
SendCorrectTopics.SaveAsync();
SceneManager.LoadScene(0);
return null;
}

Sub Sonic not closing connections

I'm using Linq from SubSonic 3 like this:
for(int x; x < 100; x++) {
var v = (from c in db.categories
where c.parent == 10
select c);
if (v.Count() > 0) return null;
category[] c = v.ToArray();
}
for some reason SubSonic is not closing the connections...so after a few runs of the above loop I run out of SQL connections in the pool or MySQL just refuses to allow more connections...I've tried this both with SS 3.0.3 and with SVN, and I keep getting these errors.
What should I be doing to close out the connections after I get a set of results?
Thanks
The problem - believe it or not - isn't SubSonic. It's the $*$&$ MySQL driver. We explicitly close off the connection when you do queries like this, but I've seen the MySQL driver completely ignore the closure in favor of some really, really lame attempts at optimization.
I don't know what to tell you here - I'm very sorry to say.
There seem to be some problems with the MySQL .NET library. A few days ago they fixed some of those issues with 6.2.2 related to releasing connections.
But there is also a problem with SubSonic. I used the LINQ templates with MySQL to generate my classes. Whenever FirstOrDefault() or First() (the other similar functions probably have the same issue).
For a query such as:
var db = new MyDb("CONNECTIONSTRING_NAME");
var userExt = (from pe in db.PhoneExtensions
where
pe.FirstName.ToLower() == firstName.ToLower() &&
pe.LastName.ToLower() == lastName.ToLower()
select pe.Extension).FirstOrDefault();
This will cause the query to be executed and the reader will not be disposed.
The problem is in Linq.Structure.DbQueryProvider in the Project of T method.
while (reader.Read())
{
yield return fnProjector(reader);
}
reader.Dispose();
The Dispose() never gets called when using FirstOrDefault() and other similar methods.
A Simple fix:
try
{
while (reader.Read())
{
yield return fnProjector(reader);
}
}
finally
{
reader.Dispose();
}
Simple quick test showing the issue:
private class DbDataReader : System.IDisposable
{
#region IDisposable Members
public void Dispose() { }
#endregion
}
private class DbQueryProvider
{
private DbDataReader _reader;
public bool IsReaderDisposed { get { return _reader == null; } }
public DbQueryProvider()
{
_reader = new DbDataReader();
}
public IEnumerable<int> Project(int numResults)
{
int i = 0;
while (i < numResults)
{
yield return i++;
}
_reader.Dispose();
_reader = null;
}
public IEnumerable<int> ProjectWithFinally(int numResults)
{
int i = 0;
try
{
while (i < numResults)
{
yield return i++;
}
}
finally
{
_reader.Dispose();
_reader = null;
}
}
}
[Test]
public void YieldReturn_Returns_TrueForIsReaderDisposed()
{
const int numResults = 1;
var qp1 = new DbQueryProvider();
var q1 = qp1.Project(numResults);
Assert.IsInstanceOf(typeof(int), q1.First());
var qp2 = new DbQueryProvider();
var q2 = qp2.Project(numResults);
Assert.IsInstanceOf(typeof(int), q2.FirstOrDefault());
var qp3 = new DbQueryProvider();
var q3 = qp3.Project(numResults);
Assert.IsInstanceOf(typeof(int), q3.Single());
var qp4 = new DbQueryProvider();
var q4 = qp4.Project(numResults);
Assert.IsInstanceOf(typeof(int), q4.SingleOrDefault());
Assert.IsTrue(qp1.IsReaderDisposed);
Assert.IsTrue(qp2.IsReaderDisposed);
Assert.IsTrue(qp3.IsReaderDisposed);
Assert.IsTrue(qp4.IsReaderDisposed);
}
[Test]
public void YieldReturnFinally_Returns_TrueForIsReaderDisposed()
{
const int numResults = 1;
var qp1 = new DbQueryProvider();
var q1 = qp1.ProjectWithFinally(numResults);
Assert.IsInstanceOf(typeof(int), q1.First());
var qp2 = new DbQueryProvider();
var q2 = qp2.ProjectWithFinally(numResults);
Assert.IsInstanceOf(typeof(int), q2.FirstOrDefault());
var qp3 = new DbQueryProvider();
var q3 = qp3.ProjectWithFinally(numResults);
Assert.IsInstanceOf(typeof(int), q3.Single());
var qp4 = new DbQueryProvider();
var q4 = qp4.ProjectWithFinally(numResults);
Assert.IsInstanceOf(typeof(int), q4.SingleOrDefault());
Assert.IsTrue(qp1.IsReaderDisposed);
Assert.IsTrue(qp2.IsReaderDisposed);
Assert.IsTrue(qp3.IsReaderDisposed);
Assert.IsTrue(qp4.IsReaderDisposed);
}
YieldReturnFinally_Returns_TrueForIsReaderDisposed passes but YieldReturn_Returns_TrueForIsReaderDisposed fails.
I have tested this on the project I am working on which will soon be in production and this seems to work without any problems. Tested with a connection pool max size of 5 and had no connection pool issues (never ran out of connections on my dev machine when doing 1 query at a time).
I also found some issues in Extensions.Database related to type changing and assignments.
I forked the project on github, committed my changes and did a pull request, hopefully that gets to the right people.

Categories