How to save elements in DB in several iterations? - c#

There are 315 webElement in allElement. I have to save 9 element each on my database table. How could I do this?
I have tried
for (var i = 0; i<=find; i++)
{
IList<IWebElement> allElement = driver.FindElements(By.XPath("//table[#class='TableText1'][2]/tbody/tr/td[contains(#class, 'Table_List') or contains(#class, 'Table_List_diff')]"));
for (int j = 0; j < allElement.Count; j=j+9)
{
var list1 = allElement.Take(j+9).ToArray();
try
{
var text = new access_event_logs();
text.USERID = list1[0].Text;
text.DEPARTMENT = list1[3].Text;
text.LOCAL_TIMESTAMP = Convert.ToDateTime(list1[4].Text);
text.EVENTID = list1[5].Text;
text.TERMINALSN = list1[6].Text;
text.PhotoPath = list1[7].Text;
text.REMARKS = list1[8].Text;
text.ACCESSMETHOD = "fp";
text.TERMINALIP = "09898";
text.PHOTO = null;
text.PHOTOSIZE = 0;
text.RECLOGFROMIP = "";
db.access_event_logs.Add(text);
db.SaveChanges();
}
}
I could save only first 9 element [0]to [8].. how can I save all the 315 element?
I have an idea. First save 9 element and then remove these element from the list. But I couldn't do this.

From Take() docs in MSDN
An IEnumerable that contains the specified number of elements from the start of the input sequence.
In allElement.Take(j+9) you always take from the beginning of the list. Since you take always the first 9 elements from the returned list it will always give you the same elements. Try GetRange instead
var list1 = allElement.GetRange(j, 9).ToArray();
Please note GetRande() won't work on IList, only on List. Change IList<IWebElement> allElement to List<IWebElement> allElement

Related

C# - Find if a specific value has a duplicate in a list

I have a use case where, given a huge list of strings and one specific string value pulled from a DataGridView row containing those same elements in the same order, I need to find if the list contains another identical entry. All the existing posts I checked just tell you if there are duplicates period. Here is what I have so far :
List<int> indexes = new List<int>{-1, originalRow.Index};
int foundIndex = CompleteScancodeList.IndexOf(originalRow.Cells[1].Value.ToString());
if (!indexes.Contains(foundIndex))
{
//Do something
}
The originalRow variable is a DataGridViewRow that is pulled from iterating over every row of a DataGridView. What I'm effectively doing here is saying : if the index of that element in the list is not -1 and not the same index as the row's index (therefore literally the same element).
I initially managed to make it work with a nested loop but it was too slow for my liking. How can I make this work the way I want where this condition will only evaluate to true if a given string value is present in a string list but at a different index than the original?
This works, kinda... It only works if the duplicated element is before the original element in the list. Similarly, if I use the LastIndexOf method, it only works if the duplicated element is after.
I'm from phone, sorry for terrible formatting and typos. So, tell if list have duplicates:
if (list.Count != list.Distinct().Count) { // list has dupes }
Find particular duplicates and handle them:
var set = new HasSet<int>();
foreach (var item in list) {
if (!set.Add(item)) {
// handle it
}
}
You can replace foreach with for loop if you need actual indexes in array.
this is an example how to find the duplicate numbers in a list and store the unique values selected from first list into the second list
List<int> LST = new List<int> { 10, 34, 43, 75, 10, 67, 30, 200, 30, 100, 30 };
List<int> LST_2 = new List<int>();
for (int i = 0; i < LST.Count; i++)
{
for (int j = i + 1; j < LST.Count; j++)
{
if (LST[j] == LST[i])
{
if (!LST_2.Contains(LST[i]))
{
LST_2.Add(LST[i]);
}
}
}
}
foreach (var N in LST_2)
{
Console.WriteLine(N);
}
i wish this help you
Once you have the first index of the value you're searching for:
string searchedValue = originalRow.Cells[1].Value.ToString();
int foundIndex = CompleteScancodeList.IndexOf(searchedValue);
You can use linq .Skip() method to get only the remaining elements. Then use .Any(), which will stop executing once the condition is met.
CompleteScancodeList.Skip(foundIndex).Any(entry => entry == searchedValue);
But it's still iterating twice, once for IndexOf and once for Any.
//Search the index of first element
int foundIndex = CompleteScancodeList.IndexOf(originalRow.Cells[1].Value.ToString());
//If the index found is row's index
if(foundIndex == originalRow.Index)
//Search the index of next element
foundIndex = CompleteScancodeList.IndexOf(originalRow.Cells[1].Value.ToString(), originalRow.Index + 1);
//If something is found
if (foundIndex != -1)
{
//Do something
}
Other solution with explicit loop :
var hasDuplicate = false;
var index = 0;
foreach(var element in CompleteScancodeList)
{
if(element == originalRow.Cells[1].Value.ToString() && index != originalRow.Index)
{
hasDuplicate = true;
break;
}
index++;
}
if (hasDuplicate)
{
//Do something
}

Error Index was out of range. Must be non-negative and less than the size of the collection

I am trying to fill my DTO objects with for, but I got this error:
Index was out of range. Must be non-negative and less than the size of the collection
Here is my code:
public static List <BankDepositHistoryDTO> DtoTODomain()
{
MyketAdsEntities context = new MyketAdsEntities();
List<BankDepositHistoryDTO> bdto = new List<BankDepositHistoryDTO>();
//var transactionlist
var transactionlist = GetListoftransactions.GetAccountingListoftransactions();
for (int i = 0; i < transactionlist.Count; i++)
{
bdto[i].AccountId = transactionlist[i].AccountId;
bdto[i].Id = transactionlist[i].Id;
bdto[i].Amount = transactionlist[i].Amount;
bdto[i].AdditionalData = transactionlist[i].AdditionalData;
bdto[i].ClientIp = transactionlist[i].ClientIp;
bdto[i].Gateway = transactionlist[i].Gateway;
bdto[i].PaymentRefNumber = transactionlist[i].PaymentRefNumber;
bdto[i].ReturnUrl = transactionlist[i].ReturnUrl;
bdto[i].State = transactionlist[i].State;
bdto[i].Uuid = transactionlist[i].Uuid;
}
return bdto;
}
I got this message at here
bdto[i].AccountId = transactionlist[i].AccountId;
You've created an empty list, and aren't adding elements to it. You must first add an element, and then update its properties:
for (int i = 0; i < transactionlist.Count; i++)
{
BankDepositHistoryDTO b = new BankDepositHistoryDTO();
b.AccountId = transactionlist[i].AccountId;
b.Id = transactionlist[i].Id;b
b.Amount = transactionlist[i].Amount;
b.AdditionalData = transactionlist[i].AdditionalData;
b.ClientIp = transactionlist[i].ClientIp;
b.Gateway = transactionlist[i].Gateway;
b.PaymentRefNumber = transactionlist[i].PaymentRefNumber;
b.ReturnUrl = transactionlist[i].ReturnUrl;
b.State = transactionlist[i].State;
b.Uuid = transactionlist[i].Uuid;
bdto.Add(b);
}
Well obvously, bdto length is less than transactionlist length.
before your for loop you can resize bdto to match transactionlist
I totally agree with #Ashkan and #Mureinik's answer, but just to improve code you can use AutoMapper. It will reduce loop and iteration for every element. It seems that all the properties between these two objects is the same.
Mapper.CreateMap<Transaction,BankDepositHistoryDTO>();
BankDepositHistoryDTO obj = Mapper.Map<Transaction,BankDepositHistoryDTO>(TransactionObj);
Also if GetListoftransactions.GetAccountingListoftransactions(); returns List<BankDepositHistoryDTO>, you can directly return that object in method.

How to add existing string array value with this code?

Variable.cs
public string[] CcEmails { get; set; }
Mail.cs
EDTO.CcEmails = dr["rsh_ccmail"].ToString().Split(';');
here i got two strings eg. xxxx#gmail.com ; yyy#gmail.com
MailProcess.cs
dataRPT1=get data from sql
EDTO.CcEmails = new string[dataRPT1.Rows.Count];
for (int i = 0; i < dataRPT1.Rows.Count; i++)
{
EDTO.CcEmails[i] = dataRPT1.Rows[i]["email_addr"].ToString();
}
Here i got list of string eg.aaa#gmail.com ......
I am try to add with existing but it add only new values..Anyone could help me..
I tend to use union, although that will remove duplicate entries. But to keep all entries you can use Concat on the array.
var emailString = "me#test.com;you#test.com";
string[] emails = emailString.Split(';');
string[] emailsFromSQL = new string[3];
emailsFromSQL[0] = "everyone#test.com";
emailsFromSQL[1] = "everyone2#test.com";
emailsFromSQL[2] = "everyone2#test.com";
//No Duplicates
var combined = emails.Union(emailsFromSQL).ToArray();
//Duplicates
var allCombined = emails.Concat(emailsFromSQL).ToArray();
Thanks
I find the easiest way of doing this is to create a list, add items to the list, then use string.Join to create the new string.
var items = new List<string>();
for (int i = 0; i < dataRPT1.Rows.Count; i++)
{
items.Add(dataRPT1.Rows[i]["email_addr"].ToString());
}
EDTO.CcEmails = string.Join(";", items);
Update after changed question:
If the type of the CcEmails is an array, the last line could be:
EDTO.CcEmails = items.ToArray();

How to Merge items within a List<> collection C#

I have a implememtation where i need to loop through a collection of documents and based on certain condition merge the documents .
The merge condition is very simple, if present document's doctype is same as later document's doctype, then copy all the pages from the later doctype and append it to the pages of present document's and remove the later document from the collection.
Note : Both response.documents and response.documents[].pages are List<> collections.
I was trying this but was getting following exception Once I remove the document.
collection was modified enumeration may not execute
Here is the code:
int docindex = 0;
foreach( var document in response.documents)
{
string presentDoctype = string.Empty;
string laterDoctype = string.Empty;
presentDoctype = response.documents[docindex].doctype;
laterDoctype = response.documents[docindex + 1].doctype;
if (laterDoctype == presentDoctype)
{
response.documents[docindex].pages.AddRange(response.documents[docindex + 1].pages);
response.documents.RemoveAt(docindex + 1);
}
docindex = docindex + 1;
}
Ex:
reponse.documents[0].doctype = "BankStatement" //page count = 1
reponse.documents[1].doctype = "BankStatement" //page count = 2
reponse.documents[2].doctype = "BankStatement" //page count = 2
reponse.documents[3].doctype = "BankStatement" //page count = 1
reponse.documents[4].doctype = "BankStatement" //page count = 4
Expected result:
response.documents[0].doctype = "BankStatement" //page count = 10
Please suggest.Appreciate your help.
I would recommend you to look at LINQ GroupBy and Distinct to process your response.documents
Example (as I cannot use your class, I give example using my own defined class):
Suppose you have DummyClass
public class DummyClass {
public int DummyInt;
public string DummyString;
public double DummyDouble;
public DummyClass() {
}
public DummyClass(int dummyInt, string dummyString, double dummyDouble) {
DummyInt = dummyInt;
DummyString = dummyString;
DummyDouble = dummyDouble;
}
}
Then doing GroupBy as shown,
DummyClass dc1 = new DummyClass(1, "This dummy", 2.0);
DummyClass dc2 = new DummyClass(2, "That dummy", 2.0);
DummyClass dc3 = new DummyClass(1, "These dummies", 2.0);
DummyClass dc4 = new DummyClass(2, "Those dummies", 2.0);
DummyClass dc5 = new DummyClass(3, "The dummies", 2.0);
List<DummyClass> dummyList = new List<DummyClass>() { dc1, dc2, dc3, dc4, dc5 };
var groupedDummy = dummyList.GroupBy(x => x.DummyInt).ToList();
Will create three groups, marked by DummyInt
Then to process the group you could do
for (int i = 0; i < groupedDummy.Count; ++i){
foreach (DummyClass dummy in groupedDummy[i]) { //this will process the (i-1)-th group
//do something on this group
//groupedDummy[0] will consists of "this" and "these", [1] "that" and "those", while [2] "the"
//Try it out!
}
}
In your case, you should create group based on doctype.
Once you create groups based on your doctype, everything else would be pretty "natural" for you to continue.
Another LINQ method which you might be interested in would be Distinct. But I think for this case, GroupBy would be the primary method you would like to use.
Use only "for loop" instead of "foreach".
foreach will hold the collection and cannot be modified while looping thru it.
Here is an example using groupBy, hope this help.
//mock a collection
ICollection<string> collection1 = new List<string>();
for (int i = 0; i < 10; i++)
{
collection1.Add("BankStatement");
}
for (int i = 0; i < 5; i++)
{
collection1.Add("BankStatement2");
}
for (int i = 0; i < 4; i++)
{
collection1.Add("BankStatement3");
}
//merge and get count
var result = collection1.GroupBy(c => c).Select(c => new { name = c.First(), count = c.Count().ToString() }).ToList();
foreach (var item in result)
{
Console.WriteLine(item.name + ": " + item.count);
}
Just use AddRange()
response.documents[0].pages.AddRange(response.documents[1].pages);
it will merge all pages of document[1] with the document[0] into document[0]

for loop "index was out of range" c# webdriver

I am getting "index out of range" from this loop. But I need to use new elements that loop founds, how do I do that? Please help to fix the problem
int linkCount = driver.FindElements(By.CssSelector("a[href]")).Count;
string[] links = new string[linkCount];
for (int i = 0; i < linkCount; i++)
{
List<IWebElement> linksToClick = driver.FindElements(By.CssSelector("a[href]")).ToList();
links[i] = linksToClick[i].GetAttribute("href");
}
I think that you could refactor your code:
var linkElements = driver.FindElements(By.CssSelector("a[href]")).ToList();
var links = new List<string>();
foreach (var elem in linkElements)
{
links.Add(elem.GetAttribute("href"));
}
If that works, you could simplify the query:
var instantLinks = driver.FindElements(By.CssSelector("a[href]"))
.Select(e => e.GetAttribute("href"))
.ToList();
You can rewrite your code to bypass the for loop:
string[] links = driver.FindElements(By.CssSelector("a[href]")).Select(l => l.GetAttribute("href")).ToArray();
This should also avoid the index out of range problem, and cut down the amount of code you have to write.
First of all i dont see a point in assigning linkstoclick values inside loop... And Reason for error must be that linksToClick list's length is more than that of linkCount.
int linkCount = driver.FindElements(By.CssSelector("a[href]")).Count;
List<string> links = new List<string>();
for (int i = 0; i < linkCount; i++)
{
List<IWebElement> linksToClick = driver.FindElements(By.CssSelector("a[href]")).ToList();
if (linksToClick.Count < i)
links.Add(linksToClick[i].GetAttribute("href"));
}
This might help with the out of range exception.
Doing this allows you to create a list of type: string without having to explicitly define the size of the list
the first one gets all of your elements by tag name ...let's assume 5.
in the loop, your driver get's all the elements by css selector, and you might have a different number here. let's say 4.
then, you might be trying to set the fifth element in a four element array.
boom.
Easiest fix to debug:
int linkCount = driver.FindElements(By.TagName("a")).Count;
string[] links = new string[linkCount];
// WRITE OUT HOM MANY links you have
for (int i = 0; i < linkCount; i++)
{
List<IWebElement> linksToClick = driver.FindElements(By.CssSelector("a[href]")).ToList();
// ASSERT THAT YOU HAVE THE SAME AMOUNT HERE
If (links.Count != linksToClick.Count)
// your logic here
links[i] = linksToClick[i].GetAttribute("href");
}

Categories

Resources