Allowing a user to select column headers to import - c#

I'm using LINQtoCSV within a program that allows the user to import an order from a CSV file. I have all the code working however, if the CSV file doesn't have the exact column headers then it doesn't work.
Below is my class that LINQtoCSV reads into -
public class orderProduct
{
public orderProduct() { }
public string product { get; set; }
public string price { get; set; }
public string orderQty { get; set; }
public string value { get; set; }
public string calculateValue()
{
return (Convert.ToDouble(price) * Convert.ToDouble(orderQty)).ToString();
}
}
If the CSV file doesn't have the exact headers it won't work. The data I actually only need is the first 4 strings.
Below is my function that actually reads in the data.
private void csvParse()
{
// order.Clear();
string fileName = txt_filePath.Text.ToString().Trim();
try
{
CsvContext cc = new CsvContext();
CsvFileDescription inputFileDescription = new CsvFileDescription
{
SeparatorChar = ',',
FirstLineHasColumnNames = true
};
IEnumerable<orderProduct> fromCSV = cc.Read<orderProduct>(fileName, inputFileDescription);
foreach (var d in fromCSV)
{
MessageBox.Show($#"Product:{d.product},Quantity:""{d.orderQty}"",Price:""{d.price}""");
orderReturn.Add(d);
}
this.DialogResult = DialogResult.Yes;
this.Close();
}
catch (Exception ex)
{
if (ex.ToString().Contains("being used by another process"))
{
MessageBox.Show("Error: Please close the file in Excel and try again");
}
else
{
MessageBox.Show(ex.ToString());
}
}
}
I want the user to be able to just pass in a file and then select the relevant columns which relate to the corresponding values and then read in the data ignoring any columns that haven't been selected.
Hope this all makes sense, is something like this possible within LINQtoCSV

You have to add IgnoreUnknownColumns = true to your CsvFileDescription
CSV:
product,price,someColumn,orderQty,value,otherColumn
my product,$123,xx,2,$246,aa
my other product,$10,yy,3,$30,bb
Working code (I modified your code a little bit, to run it in a console)
using System;
using System.Collections.Generic;
using LINQtoCSV;
namespace ConsoleApp2
{
class Program
{
static void Main(string[] args)
{
csvParse();
Console.ReadLine();
}
private static void csvParse()
{
string fileName = "../../../test.csv"; // provide a valid path to the file
CsvContext cc = new CsvContext();
CsvFileDescription inputFileDescription = new CsvFileDescription
{
SeparatorChar = ',',
FirstLineHasColumnNames = true,
IgnoreUnknownColumns = true // add this line
};
IEnumerable<orderProduct> fromCSV = cc.Read<orderProduct>(fileName, inputFileDescription);
foreach (var d in fromCSV)
{
Console.WriteLine($#"Product:{d.product},Quantity:""{d.orderQty}"",Price:""{d.price}""");
}
}
}
public class orderProduct
{
public orderProduct() { }
public string product { get; set; }
public string price { get; set; }
public string orderQty { get; set; }
public string value { get; set; }
public string calculateValue()
{
return (Convert.ToDouble(price) * Convert.ToDouble(orderQty)).ToString();
}
}
}
Output:
Product:my product,Quantity:"2",Price:"$123"
Product:my other product,Quantity:"3",Price:"$10"
If your properties have different names than CSV columns, you should use CsvColumn attribute:
public class OrderProduct
{
[CsvColumn(Name = "product")]
public string Product { get; set; }
[CsvColumn(Name = "price")]
public string Price { get; set; }
[CsvColumn(Name = "orderQty")]
public string OrderQuantity { get; set; }
public string Value { get; set; }
public string calculateValue()
{
return (Convert.ToDouble(Price) * Convert.ToDouble(OrderQuantity)).ToString();
}
}
Or if you prefer mapping columns by their indices:
public class OrderProduct
{
[CsvColumn(FieldIndex = 0)]
public string Product { get; set; }
[CsvColumn(FieldIndex = 1)]
public string Price { get; set; }
[CsvColumn(FieldIndex = 2)]
public string OrderQuantity { get; set; }
public string Value { get; set; }
public string calculateValue()
{
return (Convert.ToDouble(Price) * Convert.ToDouble(OrderQuantity)).ToString();
}
}
If you have to specify the columns on the fly, the only way seems to be to read raw data and process it yourself (the solution is based on this article):
internal class DataRow : List<DataRowItem>, IDataRow
{
}
...
int productColumnIndex = 0; // your users will provide it
var fromCSV = cc.Read<DataRow>(fileName);
foreach (var row in fromCSV)
{
var orderProduct = new OrderProduct
{
Product = row[productColumnIndex].Value,
};
Console.WriteLine(orderProduct.Product);
}

Related

No members mapped for type - CSV Helper

I am new to using CSVHelper and AutoMapper and am getting the following error when trying to:
public async Task<IActionResult> OnPostAsync()
{
if (BolCsv != null)
{
try
{
using (var reader = new StreamReader(BolCsv.OpenReadStream()))
using (var csvr = new CsvReader(reader, System.Globalization.CultureInfo.CurrentCulture))
{
csvr.Configuration.Delimiter = "\t";
csvr.Configuration.HeaderValidated = null;
csvr.Configuration.MissingFieldFound = null;
var bolDtos = csvr.GetRecords<BOLDto>().ToList();
var bols = _mapper.Map<IEnumerable<BOL>>(bolDtos);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
}
var bolDtos = csvr.GetRecords<BOLDto>();
Error: No members are mapped for type 'BOLDto'.
BOLDto:
{
public class BOLDto
{
[Name("BOLNumber")]
public int BOLNumber { get; set; }
[Name("ProductID")]
public int ProductID { get; set; }
[Name("ProductDescription")]
public string ProductDescription { get; set; }
etc...
}
}
BOL.cs:
{
public class BOL
{
public int BOLNumber { get; set; }
public int ProductId { get; set; }
public string ProductDescription { get; set; }
etc...
}
}
As I mentioned Im new to ASP.Net Core AutoMapper, and CSVHelper... how do I solve this issue?
It looks like your BOLDto class has properties, but that error message is the same as I would get if the class had fields instead of properties. So you might want to try CsvHelper.Configuration.MemberTypes.Fields. Also that must be an older version of CsvHelper you are using, because that is not how you would need to set up the configuration in the current version. But it should still work for you to add csvr.Configuration.MemberTypes = CsvHelper.Configuration.MemberTypes.Fields.
void Main()
{
var config = new MapperConfiguration(cfg => cfg.CreateMap<BOLDto, BOL>());
var _mapper = config.CreateMapper();
var csvConfig = new CsvConfiguration(CultureInfo.InvariantCulture)
{
Delimiter = "\t",
HeaderValidated = null,
MissingFieldFound = null,
MemberTypes = CsvHelper.Configuration.MemberTypes.Fields
};
using (var reader = new StringReader("BOLNumber\tProductID\tProductDescription\t\n1\t2\tMy Product"))
using (var csvr = new CsvReader(reader, csvConfig))
{
var bolDtos = csvr.GetRecords<BOLDto>().ToList();
var bols = _mapper.Map<IEnumerable<BOL>>(bolDtos);
}
}
public class BOLDto
{
[Name("BOLNumber")]
public int BOLNumber;
[Name("ProductID")]
public int ProductID;
[Name("ProductDescription")]
public string ProductDescription;
}
public class BOL
{
public int BOLNumber { get; set; }
public int ProductId { get; set; }
public string ProductDescription { get; set; }
}

Composite join on two CSV files in C#

Starting from a table of daily fruit prices
fruits.csv
Day,Name,Kind,Price
2019-09-04,"apple","red",63.09
2019-09-04,"apple","yellow",52.14
2019-09-04,"orange","navel",41.18
2019-09-04,"orange","blood",41.18
2019-09-03,"apple","red",63.07
2019-09-03,"apple","yellow",52.11
2019-09-03,"orange","navel",41.13
2019-09-03,"orange","blood",41.13
I'd like to insert the reference prices by name and kind
fruit_ref_prices.csv
Name,Kind,Reference_Price
"apple","red",60.00
"apple","yellow",50.00
"orange","navel",40.00
"orange","blood",42.00
to result in the following table
Day,Name,Kind,Price,Reference_Price
2019-09-04,"apple","red",63.09,60.00
2019-09-04,"apple","yellow",52.14,50.00
2019-09-04,"orange","navel",41.18,40.00
2019-09-04,"orange","blood",41.18,42.00
2019-09-03,"apple","red",63.07,60.00
2019-09-03,"apple","yellow",52.11,50.00
2019-09-03,"orange","navel",41.13,40.00
2019-09-03,"orange","blood",41.13,42.00
The solution should be simple using C#'s built-in SQL-like syntax, and I'm sure the answer lies in one of the following tutorial pages:
Join clause
Perform custom join operations
Join by using composite keys
but I'm having a hard time identifying the syntax of this language.
In my attempt below instead of writing
join fruit_ref in fruit_refs on fruit.name equals fruit_ref.name
I should be able to write
join fruit_ref in fruit_refs on fruit.name equals fruit_ref.name
and fruit.kind equals fruit_ref.kind
but the Boolean expression is not accepted. Why?
My attempt is:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.IO;
namespace MyConsoleApplication
{
class Program
{
const string root = #"c:\path\to\here\";
const string file1_in = root + #"fruits.csv";
const string file2_in = root + #"fruit_ref_prices.csv";
static void Main(string[] args)
{
Fruit_Basket fruit_basket = new Fruit_Basket(file1_in, file2_in);
fruit_basket.PrintFruits();
}
}
public class Fruit
{
public DateTime day { get; set; }
public string name { get; set; }
public string kind { get; set; }
public decimal price { get; set; }
public Fruit(DateTime newFruit_day,
string newFruit_name,
string newFruit_kind,
decimal newFruit_price)
{
this.day = newFruit_day;
this.name = newFruit_name;
this.kind = newFruit_kind;
this.price = newFruit_price;
}
}
public class Fruit_Ref
{
public string name;
public string kind;
public decimal reference_price;
public Fruit_Ref(string newName, string newKind, decimal newRef_Price)
{
this.name = newName;
this.kind = newKind;
this.reference_price = newRef_Price;
}
}
public class Fruit_Basket {
public List<Fruit> fruits { get; set; }
public List<Fruit_Ref> fruit_refs { get; set; }
public Fruit_Basket(string file1_in, string file2_in) {
build_fruit_list(file1_in);
build_fruit_ref_list(file2_in);
}
public void build_fruit_list(string file_in)
{
fruits = new List<Fruit>();
int count = 0;
StreamReader reader = new StreamReader(file_in);
string line = "";
while ((line = reader.ReadLine()) != null)
{
if (++count > 1)
{
string[] splitLine = line.Split(new char[] { ',' }).ToArray();
var newFruit_day = DateTime.Parse(splitLine[0]);
var newFruit_name = splitLine[1];
var newFruit_kind = splitLine[2];
var newFruit_price = decimal.Parse(splitLine[3]);
Fruit newFruit = new Fruit(newFruit_day,
newFruit_name,
newFruit_kind,
newFruit_price);
fruits.Add(newFruit);
}
}
reader.Close();
}
public void build_fruit_ref_list(string file_in)
{
fruit_refs = new List<Fruit_Ref>();
int count = 0;
StreamReader reader = new StreamReader(file_in);
string line = "";
while ((line = reader.ReadLine()) != null)
{
if (++count > 1)
{
string[] splitLine = line.Split(new char[] { ',' }).ToArray();
var newFruit_name = splitLine[0];
var newFruit_kind = splitLine[1];
var newFruit_ref_price = decimal.Parse(splitLine[2]);
Fruit_Ref newFruit_ref = new Fruit_Ref(newFruit_name,
newFruit_kind,
newFruit_ref_price);
fruit_refs.Add(newFruit_ref);
}
}
reader.Close();
}
public void PrintFruits()
{
var innerJoinQuery =
from fruit in fruits
join fruit_ref in fruit_refs on fruit.name equals fruit_ref.name
select new { Day = fruit.day, Name = fruit.name, Kind = fruit.kind,
Price = fruit.price, Reference_Price = fruit_ref.reference_price };
Console.WriteLine($#"""Date"",""Name"",""Kind"",""Price"",""Ref Price""");
foreach (var i in innerJoinQuery)
{
Console.WriteLine($#"{i.Day},{i.Kind},{i.Price},{i.Reference_Price}");
}
}
}
}
You could also refactor your code to use the CsvHelper NuGet package for reading/writing CSV files.
First, You can make these classes to reflect the fruits, fruit references and final fruit structure.
public class Fruit
{
public string Day { get; set; }
public string Name { get; set; }
public string Kind { get; set; }
public string Price { get; set; }
}
public class FruitReferencePrice
{
public string Name { get; set; }
public string Kind { get; set; }
public string Reference_Price { get; set; }
}
public class FruitFinal
{
public string Day { get; set; }
public string Name { get; set; }
public string Kind { get; set; }
public string Price { get; set; }
public string ReferencePrice { get; set; }
public override string ToString()
{
return $"Day={Day},Name={Name},Kind={Kind},Price={Price},Reference_Price={ReferencePrice}";
}
}
Then you can make two methods to return the rows of each CSV file into List<Fruit> and List<FruitReferencePrice>.
private static IEnumerable<Fruit> BuildFruitList(string csvFilePath)
{
if (!File.Exists(csvFilePath))
{
throw new FileNotFoundException("Could not locate CSV at path " + csvFilePath, csvFilePath);
}
try
{
using var fileReader = File.OpenText(csvFilePath);
using var csv = new CsvReader(fileReader);
return csv.GetRecords<Fruit>().ToList();
} catch (Exception ex)
{
Console.WriteLine(ex.Message);
return Enumerable.Empty<Fruit>();
}
}
private static IEnumerable<FruitReferencePrice> BuildFruitReferenceList(string csvFilePath)
{
if (!File.Exists(csvFilePath))
{
throw new FileNotFoundException("Could not locate CSV at path " + csvFilePath, csvFilePath);
}
try
{
using var fileReader = File.OpenText(csvFilePath);
using var csv = new CsvReader(fileReader);
return csv.GetRecords<FruitReferencePrice>().ToList();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return Enumerable.Empty<FruitReferencePrice>();
}
}
Then you can perform a grouped join and output the merged result.
var path1 = "PATH\\fruits.csv";
var path2 = "PATH\\fruit_ref_prices.csv";
var fruitList = BuildFruitList(path1);
var fruitReferencePrices = BuildFruitReferenceList(path2);
var groupedJoin = from fruit in fruitList
join fruit_ref in fruitReferencePrices
on new { fruit.Name, fruit.Kind } equals new { fruit_ref.Name, fruit_ref.Kind }
select new FruitFinal
{
Day = fruit.Day,
Name = fruit.Name,
Kind = fruit.Kind,
Price = fruit.Price,
ReferencePrice = fruit_ref.Reference_Price
};
foreach (var fruit in groupedJoin)
{
Console.WriteLine(fruit.ToString());
}
Merged results:
Day=2019-09-04,Name=apple,Kind=red,Price=63.09,Reference_Price=60.00
Day=2019-09-04,Name=apple,Kind=yellow,Price=52.14,Reference_Price=50.00
Day=2019-09-04,Name=orange,Kind=navel,Price=41.18,Reference_Price=40.00
Day=2019-09-04,Name=orange,Kind=blood,Price=41.18,Reference_Price=42.00
Day=2019-09-03,Name=apple,Kind=red,Price=63.07,Reference_Price=60.00
Day=2019-09-03,Name=apple,Kind=yellow,Price=52.11,Reference_Price=50.00
Day=2019-09-03,Name=orange,Kind=navel,Price=41.13,Reference_Price=40.00
Day=2019-09-03,Name=orange,Kind=blood,Price=41.13,Reference_Price=42.00
Please change the equals clause as on new { fruit.name, fruit.kind } equals new { fruit_ref.name, fruit_ref.kind }
Why you require this
The query has two anonymous types (one for left table and one for right table). So to compare those anonymous types, the linq statement should use new keyword
Query :
var innerJoinQuery = from fruit in fruits
join fruit_ref in fruit_refs on new { fruit.name, fruit.kind } equals new { fruit_ref.name, fruit_ref.kind }
select new { Day = fruit.day, Name = fruit.name, Kind = fruit.kind,
Price = fruit.price, Reference_Price = fruit_ref.reference_price };

how to get Json nested properties to primary one

I have below scenario:
This is my class structure :
public class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
public System.Collections.ObjectModel.Collection<Likes> Likes { get; set; }
}
public class Likes
{
public string Sport { get; set; }
public string Music { get; set; }
public string Food { get; set; }
public string Place { get; set; }
}
When I serialize object of User class then it will generate the below json string :
{"FirstName":"Naresh",
"LastName":"Parmar",
"Likes": [{"Sport":"Cricket",
"Music":"Classic",
"Food":"Gujarati",
"Place":"India"}]
}
I want to generate above json string like below:
{"FirstName":"Naresh",
"LastName":"Parmar",
"Sport":"Cricket",
"Music":"Classic",
"Food":"Gujarati",
"Place":"India"
}
I want the nested properties as primary one.
Any help would be appreciated.
Thanks in advance..
EDIT:
{"FirstName":"Naresh",
"LastName":"Parmar",
"Sport":"Cricket,Chess,Football",
"Music":"Classic",
"Food":"Gujarati",
"Place":"India"
}
It's really bad practice, since the code i'll post bellow doesn't have great maintainability, however if that's what you looking for, you can use this. Another class that have the format that you'd like, and have a method that adds a list of likes to the format you've required. That the class you should serialize to JSON:
class NestedUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Sport { get; set; }
public string Music { get; set; }
public string Food { get; set; }
public string Place { get; set; }
public void AddLikes(System.Collections.ObjectModel.Collection<Likes> likes)
{
foreach (Likes like in likes)
{
Sport += like.Sport + ",";
Music += like.Music + ",";
Food += like.Food + ",";
Place += like.Place + ",";
}
if (Sport != string.Empty)
{
Sport = Sport.Substring(0, Sport.Length - 1);
}
if (Music != string.Empty)
{
Music = Music.Substring(0, Music.Length - 1);
}
if (Food != string.Empty)
{
Food = Food.Substring(0, Food.Length - 1);
}
if (Place != string.Empty)
{
Place = Place.Substring(0, Place.Length - 1);
}
}
}
Since it's not only limited to Likes objects I'd suggest using dynamic objects. So the User class I propose is as follows:
public class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
public dynamic Details { get; set; }
public User()
{
Details = new ExpandoObject();
}
public void AddSingleDetail(string key, string value)
{
var dict = this.Details as IDictionary<string, Object>;
if (dict.ContainsKey(key))
{
dict[key] += "," + value;
}
else
{
dict[key] = value;
}
}
public void AddDetails(object detailsObject)
{
var type = detailsObject.GetType();
foreach (var prop in type.GetProperties())
{
AddSingleDetail(prop.Name, prop.GetValue(detailsObject).ToString());
}
}
}
You can use it for adding single proerpties or adding an object as a whole. I used reflection to get all the property name and values and add them to the user details.
Sample usage:
static void Main(string[] args)
{
var user1 = new User() { FirstName = "Homer", LastName = "Simpson" };
user1.AddSingleDetail("Sport", "Bowling");
user1.AddSingleDetail("Sport", "Sleeping");
user1.AddSingleDetail("Food", "Donut");
user1.AddSingleDetail("Music", "Rock");
string flattenedHomer1 = ConvertUserToFlattenedJson(user1);
var user2 = new User() { FirstName = "Homer", LastName = "Simpson" };
var likes1 = new Likes() { Food = "Donut", Music = "Rock", Place = "Springfield", Sport = "Bowling" };
var likes2 = new Likes() { Food = "Steaks", Music = "Metal", Place = "Evergreen Terrace", Sport = "Sleeping" };
var proStuff = new ProfessionalStuff() { Title = "Boss" };
user2.AddDetails(likes1);
user2.AddDetails(likes2);
user2.AddDetails(proStuff);
string flattenedHomer2 = ConvertUserToFlattenedJson(user2);
}
And the method performing the JSON conversion is:
public static string ConvertUserToFlattenedJson(User u)
{
dynamic flatUser = new ExpandoObject();
flatUser.FirstName = u.FirstName;
flatUser.LastName = u.LastName;
var dict = u.Details as IDictionary<string, Object>;
foreach (var like in dict)
{
((IDictionary<string, Object>)flatUser)[like.Key] = like.Value;
}
string json = Newtonsoft.Json.JsonConvert.SerializeObject(flatUser);
return json;
}
In my sample above user2 is converted to the following JSON string which I believe is what you are looking for:
{
"FirstName": "Homer",
"LastName": "Simpson",
"Sport": "Bowling,Sleeping",
"Music": "Rock,Metal",
"Food": "Donut,Steaks",
"Place": "Springfield,Evergreen Terrace",
"Title": "Boss"
}
While concatenating strings you can check for null or duplicate values. I didn't handle that part.
For the sake of completeness, here's the ProfessionalStuff class I made up:
public class ProfessionalStuff
{
public string Title { get; set; }
}
Hope this helps.

error when populating list based on class in generic method

I have a list defined as below in each of 11 different classes (which handle web-services)
private List<edbService> genEdbService;
internal class edbService
{
public string ServiceID { get; set; }
public string ServiceName { get; set; }
public string ServiceDescr { get; set; }
public string ServiceInterval { get; set; }
public string ServiceStatus { get; set; }
public string ServiceUrl { get; set; }
public string SourceApplication { get; set; }
public string DestinationApplication { get; set; }
public string Function { get; set; }
public string Version { get; set; }
public string userid { get; set; }
public string credentials { get; set; }
public string orgid { get; set; }
public string orgunit { get; set; }
public string customerid { get; set; }
public string channel { get; set; }
public string ip { get; set; }
}
The list is populated in each class by reading the web-service configuration data from xml files in each class:
public DCSSCustomerCreate_V3_0()
{
try
{
XElement x = XElement.Load(global::EvryCardManagement.Properties.Settings.Default.DataPath + "CustomerCreate.xml");
// Get global settings
IEnumerable<XElement> services = from el in x.Descendants("Service")
select el;
if (services != null)
{
edb_service = new List<edbService>();
// edb_service= Common.populateEDBService("CustomerCreate.xml");
foreach (XElement srv in services)
{
edbService edbSrv = new edbService();
edbSrv.ServiceID = srv.Element("ServiceID").Value;
edbSrv.ServiceName = srv.Element("ServiceName").Value;
edbSrv.ServiceDescr = srv.Element("ServiceDescr").Value;
edbSrv.ServiceInterval = srv.Element("ServiceInterval").Value;
edbSrv.ServiceStatus = srv.Element("ServiceStatus").Value;
edbSrv.ServiceUrl = srv.Element("ServiceUrl").Value;
foreach (XElement ServiceHeader in srv.Elements("ServiceHeader"))
{
...
now what I want to do is have this code in one place in my Common.cs class so I tried:
public static List<edbService> populateEDBService(string xmlDataFile)
{
try
{
XElement x = XElement.Load(global::EvryCardManagement.Properties.Settings.Default.DataPath + xmlDataFile);
// Get global settings
IEnumerable<XElement> services = from el in x.Descendants("Service")
select el;
if (services != null)
{
//edb_Service = new List<edbService>();
foreach (XElement srv in services)
{
edbService edbSrv = new edbService();
edbSrv.ServiceID = srv.Element("ServiceID").Value;
edbSrv.ServiceName = srv.Element("ServiceName").Value;
edbSrv.ServiceDescr = srv.Element("ServiceDescr").Value;
edbSrv.ServiceInterval = srv.Element("ServiceInterval").Value;
edbSrv.ServiceStatus = srv.Element("ServiceStatus").Value;
edbSrv.ServiceUrl = srv.Element("ServiceUrl").Value;
foreach (XElement ServiceHeader in srv.Elements("ServiceHeader"))
{
edbSrv.SourceApplication = ServiceHeader.Element("SourceApplication").Value;
edbSrv.DestinationApplication = ServiceHeader.Element("DestinationApplication").Value;
edbSrv.Function = ServiceHeader.Element("Function").Value;
edbSrv.Version = ServiceHeader.Element("Version").Value;
foreach (XElement ClientContext in ServiceHeader.Elements("ClientContext"))
{
edbSrv.userid = ClientContext.Element("userid").Value;
edbSrv.credentials = ClientContext.Element("credentials").Value;
edbSrv.orgid = ClientContext.Element("orgid").Value;
edbSrv.orgunit = ClientContext.Element("orgunit").Value;
edbSrv.customerid = ClientContext.Element("customerid").Value;
edbSrv.channel = ClientContext.Element("channel").Value;
edbSrv.ip = ClientContext.Element("ip").Value;
}
}
// populateEDBService.Add(edbSrv);
}
}
}
catch (Exception ex)
{
/* Write to log */
Common.logBuilder("CustomerCreate : Form --> CustomerCreate <--", "Exception", Common.ActiveMQ,
ex.Message, "Exception");
/* Send email to support */
emailer.exceptionEmail(ex);
}
return;
}
Now I get a compile error on the return; saying that An object of a type convertible to 'System.Collections.Generic.List<EvryCardManagement.Common.edbService>' is required
and in the class that should call this method, I want to do something like:
edb_service = Common.populateEDBService("CustomerUpdate.xml");
but I get an error Cannot implicitly convert type 'System.Collections.Generic.List<EvryCardManagement.Common.edbService>' to 'System.Collections.Generic.List<EvryCardManagement.CustomerUpdate.edbService>'
So firstly how should I return the list from my generic method and how should I call it to return the list populated with the configuration data?
It sounds like you have your class edbService defined in two namespaces,
EvryCardManagement.Common and
EvryCardManagement.CustomerUpdate
I would suggest defining it in only EvryCardManagement.Common and have everything reference it from there.

How to retrieve the couchbase view results using iteration?

This is my code for retrieving the list of comments from couchbase. The design document name is "Task" and the view name is: "GetComments".
public List<CommentsVO> GetComments(string TaskID, int LastCommentID, int totalCommentCount)
{
int startCount = LastCommentID - 1;
int endCount = startCount - 19;
int remainingCount = totalCommentCount - endCount;
if (endCount < 0)
{
endCount = 0;// totalCommentCount - remainingCount;
}
IView<CommentsVO> results = oCouchbase.GetView<CommentsVO>("Task", "GetComments");
results.StartKey(new object[] { TaskID, startCount }).EndKey(new object[] { TaskID, endCount });
if (results != null)
{
List<CommentsVO> resultlist = new List<CommentsVO>();
foreach (CommentsVO vo in results)//Here it is not entering inside the loop... Am i missing anything in this condition
{
resultlist.Add(vo);
}
resultlist.Reverse();
return resultlist;
}
return null;
}
My CommentsVo code is:
public class CommentsVO
{
public CommentsVO()
{
CommentedOn = Convert.ToString(DateTime.Now);
IsActive = "1";
}
[JsonIgnore]
public string TaskID { get; set; }
[JsonProperty("commented_user_id")]
public string CommentedUserID { get; set; }
[JsonProperty("commented_user_name")]
public string CommentedUserName { get; set; }
[JsonProperty("comment_description")]
public string CommentDescription { get; set; }
[JsonProperty("commented_on")]
public string CommentedOn { get; set; }
[JsonProperty("is_active")]
public string IsActive { get; set; }
[JsonProperty("seq")]
public string Sequence { get; set; }
}
My couchbase view code is:
function(doc) {
for(var i in doc.comments) {
emit([doc._id,doc.comments[i].seq],doc.comments[i]);
}
}
I have tried without using startkey and endkey its iterating but when i tried using startkey and endkey it is not entering inside the loop..
Kindly help me out..
When using a composite key, you would specify an array of keys in StartKey/EndKey. In your code, you're actually overwriting the keys with your second calls to StarKey and EndKey.
So something like:
results.StartKey(new object[] { TaskId, startCount }).EndKey(new object[] { TaskId, endCount });

Categories