Data grouping by date and converting DateTime to Double - c#

can anyone help me with this, I'm getting the result at the moment:
I want the data in the Stunden column to convert to Double and sort by date
At the end result to be 01.03.2017 = 9.0;
13.12.2017 = 8.5;
this is my current code
q.ZPZ_LPE_ID = userID;
if (db.State == ConnectionState.Closed)
db.Open();
string query = "SELECT zei.ZPZ_Von, zei.ZPZ_Bis, per.LPE_Nr, zei.ZPZ_LPE_ID, zei.ZPZ_Datum, SUM (zei.ZPZ_Std100) AS ZPZ_Std100" +
" FROM DB.dbo.Z_PRAESENZZEIT zei INNER JOIN DB.dbo.A_PERSONAL per ON zei.ZPZ_LPE_ID = per.LPE_ID" +
$" WHERE zei.ZPZ_Datum BETWEEN '{dtFromDate.Value}' AND '{dtToDate.Value}' AND zei.ZPZ_LPE_ID='{userID.ToString()}' GROUP BY per.LPE_Nr, zei.ZPZ_LPE_ID, zei.ZPZ_Datum, zei.ZPZ_Von, zei.ZPZ_Bis ORDER BY zei.ZPZ_Datum, per.LPE_Nr;";
using (SqlCommand cmd = new SqlCommand(query, db))
{
using (SqlDataAdapter da = new SqlDataAdapter(cmd))
{
using (SqlDataReader dr = cmd.ExecuteReader())
{
var items = new BindingList<PRAESENZZEIT>();
while (dr.Read())
{
PRAESENZZEIT pra = new PRAESENZZEIT();
pra.ZPZ_Datum = Convert.ToDateTime(dr["ZPZ_Datum"]);
pra.ZPZ_Von = Convert.ToDateTime(dr["ZPZ_Von"]);
if (pra.ZPZ_Von.TimeOfDay < new TimeSpan(8, 5, 0))
pra.ZPZ_Von = new DateTime(pra.ZPZ_Von.Year, pra.ZPZ_Von.Month, pra.ZPZ_Von.Day, 8, 0, 0);
// DateTime gehen = DateTime.Now;
pra.ZPZ_Bis = Convert.ToDateTime(dr["ZPZ_Bis"]);
pra.arbeitszeit = pra.ZPZ_Bis - pra.ZPZ_Von;
// Convert.ToString(Convert.ToInt32(arbeitszeit));
items.Add(pra);
}
pRAESENZZEITBindingSource.DataSource = items;
}
}
}
}
this is the PRAESENZEIT class
public class PRAESENZZEIT
{
public int LPE_Nr { get; set; }
public DateTime ZPZ_Datum { get; set; }
public double ZPZ_Std100 { get; set; }
public int ZPZ_LPE_ID { get; set; }
public DateTime ZPZ_Von { get; set; }
public DateTime ZPZ_Bis { get; set; }
public DateTime ZPZ_Std { get; set; }
public int ZPZ_ID { get; set; }
public int ZPZ_Jahr { get; set; }
public int ZPZ_Monat { get; set; }
public int ZPZ_Tag { get; set; }
public DateTime ZPZ_ERFDAT { get; set; }
public string ZPZ_ERFUSER { get; set; }
public DateTime ZPZ_MUTDAT { get; set; }
public string ZPZ_MUTUSER { get; set; }
public TimeSpan arbeitszeit { get; set; }
}
Thank you all for help
mysql query result

If Studen is a TimeSpan you can sum it that way.
var dataSource = new List<grdata> {
// StartDate , EndDate
new grdata("01/03/2017 04:00","01/03/2017 08:00"),
new grdata("01/03/2017 09:00","01/03/2017 14:00"),
new grdata("13/12/2017 04:30","13/12/2017 09:00"),
new grdata("13/12/2017 10:00","13/12/2017 14:00")
};
var opdata = dataSource.Select(x => new
{
date = DateTime.Parse(x.start.ToShortDateString()) ,
time = x.end-x.start
});
var result = opdata.GroupBy(x => x.date)
.Select(g => new
{
date = g.Key,
sumTime = new TimeSpan(g.Sum(y => y.time.Ticks))
});
var totalSum = new TimeSpan(opdata.Sum(y => y.time.Ticks));
Result:
{ date = {01/03/2017 00:00:00}, sumTime = {00:09:00} }
{ date = {13/12/2017 00:00:00}, sumTime = {00:08:30} }

I guess you want to group by day. You can check if you already added the day and add the time to arbeitszeit. However then the fields 'von' and 'bis' are useless. This is basically because the class design is quite bad. You could have a class ArbeitsTag which contains a property List<Anwesenheit> and a property Gesamtzeit aka Totaltime where you sum up all the times. But that's a different story ;-)
var items = new BindingList<PRAESENZZEIT>();
while (dr.Read())
{
PRAESENZZEIT pra = null;
DateTime datum = Convert.ToDateTime(dr["ZPZ_Datum"]);
//calculate parse from and to. Don't store it to Präsenzzeit as it will be accumulated. Therefore it will always be wrong. possible solution would be to store each "phase" separatly and calculate a Total time from there...
DateTime von = Convert.ToDateTime(dr["ZPZ_Von"]);
if (von.TimeOfDay < new TimeSpan(8, 5, 0))
von = new DateTime(von.Year, von.Month, von.Day, 8, 0, 0);
DateTime bis = Convert.ToDateTime(dr["ZPZ_Bis"]);
pra = items.FirstOrDefault(x => x.ZPZ_Datum == datum);
//check if day was already added
if (pra != null)
{
pra.arbeitszeit = pra.arbeitszeit + (bis - von);
}
else
{
pra = new PRAESENZZEIT();
pra.ZPZ_Datum = datum;
// DateTime gehen = DateTime.Now;
pra.arbeitszeit = bis - von;
// Convert.ToString(Convert.ToInt32(arbeitszeit));
items.Add(pra);
}
}

Related

Resampling with Deedle duplicate keys

My code below resamples 5-minute interval to 1-day interval for the daily profit stats. The problem is that BacktestResult consists of duplicate CloseDate values, because I'm testing with multiple pairs (TRXUSDT, ETHUSDT and BTCUSDT). dailyProfit returns Series<DateTime, double>, which explains the exception. How can I make it grouped by Pair or something? It works fine when tested with one pair.
// Create series
var series = _backtestResults.ToOrdinalSeries();
// daily_profit = results.resample('1d', on = 'close_date')['profit_percent'].sum()
var dailyProfit = series.ResampleEquivalence(
index => new DateTime(series[index].CloseDate.Year, series[index].CloseDate.Month, series[index].CloseDate.Day, 0, 0, 0, DateTimeKind.Utc),
group => group.SelectValues(g => g.ProfitPercentage).Sum()).DropMissing();
// classes
public class BacktestResult
{
public string Pair { get; set; }
public decimal ProfitPercentage { get; set; }
public decimal ProfitAbs { get; set; }
public decimal OpenRate { get; set; }
public decimal CloseRate { get; set; }
public DateTime OpenDate { get; set; }
public DateTime CloseDate { get; set; }
public decimal OpenFee { get; set; }
public decimal CloseFee { get; set; }
public decimal Amount { get; set; }
public decimal TradeDuration { get; set; }
public SellType SellReason { get; set; }
}
Edit:
Example which takes the JSON data from pastebin:
using Deedle;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
namespace Resample
{
class Program
{
public class BacktestResultTest
{
public string Pair { get; set; }
public decimal ProfitPercentage { get; set; }
public decimal ProfitAbs { get; set; }
public decimal OpenRate { get; set; }
public decimal CloseRate { get; set; }
public DateTime OpenDate { get; set; }
public DateTime CloseDate { get; set; }
public decimal OpenFee { get; set; }
public decimal CloseFee { get; set; }
public decimal Amount { get; set; }
public decimal TradeDuration { get; set; }
public bool OpenAtEnd { get; set; }
public int SellReason { get; set; }
}
static void Main(string[] args)
{
// Take JSON data from pastebin
using var webClient = new WebClient();
var json = webClient.DownloadString("https://pastebin.com/raw/Dhp9202f");
// Deserialize the data
var data = JsonConvert.DeserializeObject<List<BacktestResultTest>>(json);
var ts = data.ToOrdinalSeries();
var byDateAndPair = ts.SelectKeys(kvp => Tuple.Create(kvp.Value.Value.CloseDate, kvp.Value.Value.Pair)).SortByKey();
// daily_profit = results.resample('1d', on = 'close_date')['profit_percent'].sum()
var dailyProfit2 = byDateAndPair.ResampleEquivalence(
k => Tuple.Create(new DateTime(k.Item1.Year, k.Item1.Month, k.Item1.Day), k.Item2),
g => g.Select(kvp => kvp.Value.ProfitPercentage).Sum());
// backtest_worst_day = min(daily_profit)
var worstDay2 = dailyProfit2.Min();
// backtest_best_day = max(daily_profit)
var bestDay2 = dailyProfit2.Max();
// winning_days = sum(daily_profit > 0)
var winningDays2 = dailyProfit2.SelectValues(x => x > 0).Sum();
// draw_days = sum(daily_profit == 0)
var drawDays2 = dailyProfit2.SelectValues(x => x == 0).Sum();
// losing_days = sum(daily_profit < 0)
var losingDays2 = dailyProfit2.SelectValues(x => x < 0).Sum();
Console.ReadLine();
}
}
}
You can use a custom data type as a key in Deedle. If you want to be able to use resampling on the series, then this needs to support IComparable. You can either define your own type or use built-in Tuple.
Assuming we have some very basic data:
var ts =
new[] {
KeyValue.Create(new DateTime(2020,1,1), new { Value = 1.0, Kind = "A" }),
KeyValue.Create(new DateTime(2020,1,2), new { Value = 1.0, Kind = "A" }),
KeyValue.Create(new DateTime(2020,1,3), new { Value = 1.0, Kind = "B" }),
KeyValue.Create(new DateTime(2020,1,4), new { Value = 1.0, Kind = "B" }),
}.ToSeries();
The first thing we need to do is to change the key to be the date together with a kind. (In fact, you can get into trouble earlier in your code if you had duplicate dates!)
var byDateAndKind =
ts.SelectKeys(kvp => Tuple.Create(kvp.Key, kvp.Value.Value.Kind)).SortByKey();
Now the key is Tuple<DateTime, string> consisting of the date and the kind. You can now use ResampleEquivalence on this. Here, we use year and kind as the new key and sum values in group:
var aggByYearAndKind =
byDateAndKind.ResampleEquivalence(
(k) => Tuple.Create(k.Item1.Year, k.Item2),
(g) => g.Select(kvp => kvp.Value.Value).Sum());
aggByYearAndKind.Print();
This will print a series that maps 2020, "A" to 2 and also 2020, "B" to 2.
EDIT You are right - this does not seem to work. I was able to get it to work using GroupBy instead of ResampleEquvialence:
var dailyProfit2 =
ts.GroupBy(kvp =>
new { Date = new DateTime(kvp.Value.CloseDate.Year, kvp.Value.CloseDate.Month, kvp.Value.CloseDate.Day), Kind = kvp.Value.Pair })
.SelectValues(g => g.Select(kvp => kvp.Value.ProfitPercentage).Values.Sum());
// backtest_worst_day = min(daily_profit)
var worstDay2 = dailyProfit2.Min();
// backtest_best_day = max(daily_profit)
var bestDay2 = dailyProfit2.Max();
// winning_days = sum(daily_profit > 0)
var winningDays2 = dailyProfit2.Where(x => x.Value > 0).Values.Sum();
// draw_days = sum(daily_profit == 0)
var drawDays2 = dailyProfit2.Where(x => x.Value == 0).Values.Sum();
// losing_days = sum(daily_profit < 0)
var losingDays2 = dailyProfit2.Where(x => x.Value < 0).Values.Sum();

Map one class data to another class with iteration

I have a C# project and looking for simple solution for map one class object data to list of another class object.
This is my input class
public class RatesInput
{
public string Type1 { get; set; }
public string Break1 { get; set; }
public string Basic1 { get; set; }
public string Rate1 { get; set; }
public string Type2 { get; set; }
public string Break2 { get; set; }
public string Basic2 { get; set; }
public string Rate2 { get; set; }
public string Type3 { get; set; }
public string Break3 { get; set; }
public string Basic3 { get; set; }
public string Rate3 { get; set; }
}
This is my another class structure
public class RateDetail
{
public string RateType { get; set; }
public decimal Break { get; set; }
public decimal Basic { get; set; }
public decimal Rate { get; set; }
}
it has a object like below. (For easiering the understanding, I use hardcoded values and actually values assign from a csv file)
RatesInput objInput = new RatesInput();
objInput.Type1 = "T";
objInput.Break1 = 100;
objInput.Basic1 = 50;
objInput.Rate1 = 0.08;
objInput.Type2 = "T";
objInput.Break2 = 200;
objInput.Basic2 = 50;
objInput.Rate2 = 0.07;
objInput.Type3 = "T";
objInput.Break3 = 500;
objInput.Basic3 = 50;
objInput.Rate3 = 0.06;
Then I need to assign values to "RateDetail" list object like below.
List<RateDetail> lstDetails = new List<RateDetail>();
//START Looping using foreach or any looping mechanism
RateDetail obj = new RateDetail();
obj.RateType = //first iteration this should be assigned objInput.Type1, 2nd iteration objInput.Type2 etc....
obj.Break = //first iteration this should be assigned objInput.Break1 , 2nd iteration objInput.Break2 etc....
obj.Basic = //first iteration this should be assigned objInput.Basic1 , 2nd iteration objInput.Basic2 etc....
obj.Rate = //first iteration this should be assigned objInput.Rate1, 2nd iteration objInput.Rate2 etc....
lstDetails.Add(obj); //Add obj to the list
//END looping
Is there any way to convert "RatesInput" class data to "RateDetail" class like above method in C#? If yes, how to iterate data set?
Try this:
public class RatesList : IEnumerable<RateDetail>
{
public RatesList(IEnumerable<RatesInput> ratesInputList)
{
RatesInputList = ratesInputList;
}
private readonly IEnumerable<RatesInput> RatesInputList;
public IEnumerator<RateDetail> GetEnumerator()
{
foreach (var ratesInput in RatesInputList)
{
yield return new RateDetail
{
RateType = ratesInput.Type1,
Break = Convert.ToDecimal(ratesInput.Break1, new CultureInfo("en-US")),
Basic = Convert.ToDecimal(ratesInput.Basic1, new CultureInfo("en-US")),
Rate = Convert.ToDecimal(ratesInput.Rate1, new CultureInfo("en-US"))
};
yield return new RateDetail
{
RateType = ratesInput.Type2,
Break = Convert.ToDecimal(ratesInput.Break2),
Basic = Convert.ToDecimal(ratesInput.Basic2),
Rate = Convert.ToDecimal(ratesInput.Rate2, new CultureInfo("en-US"))
};
yield return new RateDetail
{
RateType = ratesInput.Type3,
Break = Convert.ToDecimal(ratesInput.Break3),
Basic = Convert.ToDecimal(ratesInput.Basic3),
Rate = Convert.ToDecimal(ratesInput.Rate3, new CultureInfo("en-US"))
};
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
And use:
var list = new RatesList(new List<RatesInput>() { objInput });
foreach (var item in list)
{
Console.WriteLine(item.Basic);
}
You can use Reflection to get the properties info like this:
var props = objInput.GetType().GetProperties();
var types = props.Where(x => x.Name.StartsWith("Type"))
.Select(x => x.GetValue(objInput)).ToList();
var breaks = props.Where(x => x.Name.StartsWith("Break"))
.Select(x => x.GetValue(objInput)).ToList();
var basics = props.Where(x => x.Name.StartsWith("Basic"))
.Select(x => x.GetValue(objInput)).ToList();
var rates = props.Where(x => x.Name.StartsWith("Rate"))
.Select(x => x.GetValue(objInput)).ToList();
List<RateDetail> lstDetails = new List<RateDetail>();
for (int i = 0; i < types.Count; i++)
{
lstDetails.Add(new RateDetail
{
RateType = types[i].ToString(),
Break = Convert.ToDecimal(breaks[i]),
Basic = Convert.ToDecimal(basics[i]),
Rate = Convert.ToDecimal(rates[i])
});
}

select a day from a period - reccurrence

I am trying to implement a recurrence pattern for my Calendar Application.
I want it to work the same way Outlook does when you set an appointment with reccurrence.
public async Task<ValidationResponse<ReccurrenceModel>> ApplyReccurrencePeriod (string userName, ReccurrenceModel value)
{
var user = await repository.FindByUserName(userName);
var fromDateUTC = DateTime.SpecifyKind(value.FromDate, DateTimeKind.Utc);
var toDateUTC = DateTime.SpecifyKind(value.ToDate, DateTimeKind.Utc);
var dates = new List<DateTime>();
var weeklyReccurrence = value.weeklyReccurrence;
if (value.IsMonday == true)
{
var fromDate = value.FromDate;
var toDate = value.ToDate;
for (var dt = fromDate; dt < toDate; dt = dt.AddDays(1))
{
dates.Add(dt);
}
var savedDates = dates.Where(x => x.DayOfWeek == DayOfWeek.Monday).Select(x => x.Date);
}
// I do the same code to verify every week day
var test = dates.Where(x => x.DayOfWeek == DayOfWeek.Friday).Select(x => x.Date);
}
foreach (var date in savedDates) {
var x = user.Holidays.FirstOrDefault(kvp => kvp.Key == date
&& kvp.Value.StateVal == value.State.StateVal);
var dateUTC = DateTime.SpecifyKind(date, DateTimeKind.Utc);
user.Holidays[dateUTC] = value.State;
}
// save
var updatedUser = await repository.UpdateEmployee(user);
return await Task.FromResult(new ValidationResponse<HolidayModel>()
{
IsValid = true,
Result = updatedUser.Holidays.ContainsKey(dateUTC) ? new HolidayModel() { Date = dateUTC, State = updatedUser.Holidays[dateUTC] } : null
});
}
}
The problem with my code is that it works only if I have weekly reccurrence. I need to make it work in order to have 2, 3, ... n weeks reccurrence.
How can I make it skip some weeks?
public class ReccurrenceModel
{
public DateTime FromDate { get; set; }
public DateTime ToDate { get; set; }
public int WeeklyReccurrence { get; set; }
public State State { get; set; }
public bool IsMonday { get; set; }
public bool IsTuesday { get; set; }
public bool IsWednesday { get; set; }
public bool IsThursday { get; set; }
public bool IsFriday { get; set; }
public DateTime FromDateToReturn { get; set; }
public DateTime ToDateToReturn { get; set; }
}
The code is a bit convoluted, there are a lot of lines that do nothing at all.
Here I provide a sample of code that, albeit not elegant at all, provides you with the behaviour you need, the following code will create a list of days that are recurrent every 2, 3, whatever you need weeks you define in its call.
This method also accepts a list of DayOfWeek for which you want the recurrence to be created
private static void GetRecurrentDays(DateTime fromDate, DateTime untilDate, uint weeklyRecurrence, List<DayOfWeek> recurrenceDays)
{
var recurrenceDates = new List<DateTime>();
for (var dt = fromDate; dt < untilDate; dt = dt.AddDays(1))
{
if (recurrenceDays.Any(day => day.Equals(dt.DayOfWeek)))
{
var lastDate =
recurrenceDates
.LastOrDefault(date => date.DayOfWeek.Equals(dt.DayOfWeek));
// We multiply 7 days (a week) with weeklyRecurrence to
// calculate the appropiate date in which to add another day,
// calling with either 0 or 1 will calculate a weekly
// schedule
if (lastDate.Equals(DateTime.MinValue)
|| weeklyRecurrence.Equals(0)
|| ((dt - lastDate).Days % (7 * weeklyRecurrence)).Equals(0) )
{
recurrenceDates.Add(dt);
}
}
}
}
you can embed this code in yours in order to obtain the days with weekly recurrence and then, consume them further in your code

Read hierarchical XML and flatten into a List of objects?

I have an XML document which I would like to read, flatten, and return a List<> of an object I called PMRow. For each CodingRow in the XML there should be a corresponding List element and the "header" details of the Invoice should simply repeat. Many of the XML elements will be ignored in this transformation at both the Invoice and CodingRow level. I've started writing the code below and I can't conceptualize where to go from there:
Incomplete code:
public static List<PMRow> ParseToPMRows(FileInfo myFile)
{
var xDoc = XDocument.Load(myFile.FullName);
var query = from element in xDoc.Element("InvoiceDocument").Element("Invoice").Element("CodingRows").Elements("CodingRow")
select
}
Target Class:
public class PMRow
{
public string SupplierCode { get; set; }
public string InvoiceNumber { get; set; }
public DateTime InvoiceDate { get; set; }
public decimal GrossSum { get; set; }
public decimal NetSum { get; set; }
public decimal TaxSum { get; set; }
public decimal CR_GrossSum { get; set; }
public string AccountNumber { get; set; }
public string DimCode1 { get; set; }
}
XML Docuemnt:
<InvoiceDocument>
<Method>Post</Method>
<Invoice>
<GrossSum nil="False">700.000000</GrossSum>
<InvoiceDate nil="False">2018-09-26</InvoiceDate>
<InvoiceNumber nil="False">180928003802901</InvoiceNumber>
<NetSum nil="False">700.000000</NetSum>
<PaidSum nil="False">0.000000</PaidSum>
<PaymentBlock nil="False">false</PaymentBlock>
<PaymentDate nil="False">0001-01-01</PaymentDate>
<SupplierCode nil="False">AQUINC</SupplierCode>
<SupplierParentId nil="False"></SupplierParentId>
<TaxCode nil="False"></TaxCode>
<TaxPercent nil="False">0.000000</TaxPercent>
<TaxPercent2 nil="False">0.000000</TaxPercent2>
<TaxSum nil="False">0.000000</TaxSum>
<OrderNumber nil="False"></OrderNumber>
<OrderInCoding nil="False" />
<CodingRows>
<CodingRow>
<GrossSum nil="False">500.000000</GrossSum>
<InternalStatus nil="False">Loaded</InternalStatus>
<AccountCode nil="False">1990</AccountCode>
<AccountName nil="False">Gain on Non-Operating Asset</AccountName>
<DimCode1 nil="False">01</DimCode1>
<DimName1 nil="False">Operating/Unrestricted</DimName1>
<MaterialGroup nil="False"></MaterialGroup>
<FiscalYear nil="False"></FiscalYear>
<DimCode3 nil="False">06</DimCode3>
<DimName3 nil="False">Sports</DimName3>
<DimCode4 nil="False">06500</DimCode4>
<DimName4 nil="False">Personal Training</DimName4>
<DimCode5 nil="False">6</DimCode5>
<DimName5 nil="False">Minneapolis</DimName5>
<DimCode6 nil="False"></DimCode6>
<DimName6 nil="False"></DimName6>
</CodingRow>
<CodingRow>
<GrossSum nil="False">200.000000</GrossSum>
<InternalStatus nil="False">Loaded</InternalStatus>
<AccountCode nil="False">2390</AccountCode>
<AccountName nil="False">Gain on Non-Operating Asset</AccountName>
<DimCode1 nil="False">02</DimCode1>
<DimName1 nil="False">Operating/Unrestricted</DimName1>
<MaterialGroup nil="False"></MaterialGroup>
<FiscalYear nil="False"></FiscalYear>
<DimCode3 nil="False">06</DimCode3>
<DimName3 nil="False">Sports</DimName3>
<DimCode4 nil="False">06500</DimCode4>
<DimName4 nil="False">Personal Training</DimName4>
<DimCode5 nil="False">6</DimCode5>
<DimName5 nil="False">Minneapolis</DimName5>
<DimCode6 nil="False"></DimCode6>
<DimName6 nil="False"></DimName6>
</CodingRow>
</CodingRows>
<InvoiceRows />
</Invoice>
Conceptualized target (two objects of type PMRow in a List):
AQUINC, 180928003802901, 9/26/2018, 700, 700, 0, 500, 1990, 01
AQUINC, 180928003802901, 9/26/2018, 700, 700, 0, 200, 2390, 02
Is this what you are looking for?
XElement invoice = xDoc.Root.Element("Invoice");
List<PMRow> rows = invoice
.Element("CodingRows")
.Elements("CodingRow")
.Select(codingRow => new PMRow
{
SupplierCode = invoice.Element("SupplierCode").Value,
InvoiceNumber = invoice.Element("InvoiceNumber").Value,
InvoiceDate = DateTime.Parse(invoice.Element("InvoiceDate").Value),
GrossSum = decimal.Parse(invoice.Element("GrossSum").Value),
NetSum = decimal.Parse(invoice.Element("NetSum").Value),
TaxSum = decimal.Parse(invoice.Element("TaxSum").Value),
CR_GrossSum = decimal.Parse(codingRow.Element("GrossSum").Value),
AccountNumber = codingRow.Element("AccountCode").Value,
DimCode1 = codingRow.Element("DimCode1").Value,
})
.ToList();
Note: the above assumes that all elements will be present and valid. If this is not the case, you will need to add appropriate handling for that.
Fiddle: https://dotnetfiddle.net/DjKcDg
I generally find more convenient to first serialize XML into class object and then iterate over serialzed object.
You only need
XmlSerializer serializer = new XmlSerializer(typeof(Invoice));
TextReader reader = new StringReader(source);
Invoice resultObj = (Invoice)serializer.Deserialize(reader);
var pmRows = resultObj.CodingRows.CodingRow.Select(item => new PMRow
{
CR_GrossSum = Convert.ToDecimal(resultObj.GrossSum.Text),
InvoiceDate = Convert.ToDateTime(resultObj.InvoiceDate.Text),
InvoiceNumber = resultObj.InvoiceNumber.Text,
SupplierCode = resultObj.SupplierCode.Text,
NetSum = Convert.ToDecimal(resultObj.NetSum.Text),
GrossSum = Convert.ToDecimal(resultObj.GrossSum.Text),
TaxSum = Convert.ToDecimal(resultObj.TaxSum.Text),
AccountNumber = item.AccountCode.Text,
DimCode1 = item.DimCode1.Text
}).ToList();
you can check my solution from https://dotnetfiddle.net/jr11hB
Try code below. I assumed they are multiple Invoice in a file so I had to use SelectMany() to return a flat list
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication75
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
ParseToPMRows(FILENAME);
}
public static List<PMRow> ParseToPMRows(string myFile)
{
XDocument xDoc = XDocument.Load(myFile);
var tempResults = xDoc.Descendants("Invoice").Select(x => new {
supplierCode = (string)x.Element("SupplierCode"),
invoiceNumber = (string)x.Element("InvoiceNumber"),
invoiceDate = (DateTime)x.Element("InvoiceDate"),
grossSum = (decimal)x.Element("GrossSum"),
netSum = (decimal)x.Element("NetSum"),
taxSum = (decimal)x.Element("TaxSum"),
codingRows = x.Descendants("CodingRow").Select(y => new {
crGrossSum = (decimal)y.Element("GrossSum"),
accounNumber = (string)y.Element("AccountCode"),
dimCode1 = (string)y.Element("DimCode1")
}).ToList()
}).ToList();
List<PMRow> rows = tempResults.Select(x => x.codingRows.Select(y => new PMRow()
{
SupplierCode = x.supplierCode,
InvoiceNumber = x.invoiceNumber,
InvoiceDate = x.invoiceDate,
GrossSum = x.grossSum,
NetSum = x.netSum,
TaxSum = x.taxSum,
CR_GrossSum = y.crGrossSum,
AccountNumber = y.accounNumber,
DimCode1 = y.dimCode1
})).SelectMany(x => x).ToList();
return rows;
}
}
public class PMRow
{
public string SupplierCode { get; set; }
public string InvoiceNumber { get; set; }
public DateTime InvoiceDate { get; set; }
public decimal GrossSum { get; set; }
public decimal NetSum { get; set; }
public decimal TaxSum { get; set; }
public decimal CR_GrossSum { get; set; }
public string AccountNumber { get; set; }
public string DimCode1 { get; set; }
}
}
For one Invoice you can use following :
public static List<PMRow> ParseToPMRows(string myFile)
{
XDocument xDoc = XDocument.Load(myFile);
var tempResults = xDoc.Descendants("Invoice").Select(x => new {
supplierCode = (string)x.Element("SupplierCode"),
invoiceNumber = (string)x.Element("InvoiceNumber"),
invoiceDate = (DateTime)x.Element("InvoiceDate"),
grossSum = (decimal)x.Element("GrossSum"),
netSum = (decimal)x.Element("NetSum"),
taxSum = (decimal)x.Element("TaxSum"),
codingRows = x.Descendants("CodingRow").Select(y => new {
crGrossSum = (decimal)y.Element("GrossSum"),
accounNumber = (string)y.Element("AccountCode"),
dimCode1 = (string)y.Element("DimCode1")
}).ToList()
}).FirstOrDefault();
List<PMRow> rows = tempResults.codingRows.Select(x => new PMRow()
{
SupplierCode = tempResults.supplierCode,
InvoiceNumber = tempResults.invoiceNumber,
InvoiceDate = tempResults.invoiceDate,
GrossSum = tempResults.grossSum,
NetSum = tempResults.netSum,
TaxSum = tempResults.taxSum,
CR_GrossSum = x.crGrossSum,
AccountNumber = x.accounNumber,
DimCode1 = x.dimCode1
}).ToList();
return rows;
}

Remove/Replace comma from CSV file when using entity framework?

I have come across this issue and I can't solve it and it's driving me insane. I've created an C# app that reads a csv file, then inserts the information into MSSQL. When I do this though, I'm getting some skewed inserts. Everything inserts fine until there is a comma within double quotes.. for example, if the Bank Name is "Capital One,Inc" it will insert 'Inc' into the next column. I have tried removing the comma's, but I'm getting the same results. I am using the entity framework to do this.. this is how my dataclass is set up.
namespace CIT
{
class RawData
{
public string Branch { get; set; }
public string Pfx { get; set; }
public string AcctNo { get; set; }
public string CustName { get; set; }
public string CtrlNo { get; set; }
public string RefNo { get; set; }
public string Days { get; set; }
public string DealNoCat { get; set; }
public string BankNameFiCat { get; set; }
public string FinMgrName { get; set; }
public string Desc { get; set; }
public string DealDateCat { get; set; }
public string SchedNo { get; set; }
public string SchedTypeDv { get; set; }
public string SchedRemarks { get; set; }
public string Amt { get; set; }
public string Src { get; set; }
public string SysDateCat { get; set; }
public string JrnlDateDv { get; set; }
public string DateY4 { get; set; }
public string DaysOut { get; set; }
public RawData(string csvString)
{
string[] citData = csvString.Replace(", ", " ").Replace(".", " ").Split(',');
try
{
Branch = citData[0].Replace("\"", "");
Pfx = citData[1].Replace("\"", "");
AcctNo = citData[2].Replace("\"", "");
CustName = citData[3].Replace("\"", "");
CtrlNo = citData[4].Replace("\"", "");
RefNo = citData[5].Replace("\"", "");
Days = citData[6].Replace("\"", "");
DealNoCat = citData[7].Replace("\"", "");
BankNameFiCat = citData[8].Replace("\"", "");
FinMgrName = citData[9].Replace("\"", "");
Desc = citData[10].Replace("\"", "");
DealDateCat = citData[11].Replace("\"", "");
SchedNo = citData[12].Replace("\"", "");
SchedTypeDv = citData[13].Replace("\"", "");
SchedRemarks = citData[14].Replace("\"", "");
Amt = citData[15].Replace("\"", "");
Src = citData[16].Replace("\"", "");
SysDateCat = citData[17].Replace("\"", "");
JrnlDateDv = citData[18].Replace("\"", "");
DateY4 = citData[19].Replace("\"", "");
DaysOut = null;
}
catch (Exception ex)
{
Console.WriteLine("Something went wrong. " + ex.ToString());
}
}
}
}
I have also tried
BankNameFiCat = citData[8].Replace(",", " ").Replace("\"", "");
but I have no had any luck with that. I think the problem is that the comma has no spaces before or after it. It is like "Capital One,Inc" and it's like that with other bank names as well.
This is how I'm uploading the file to the list then writing it to the db..
string text = File.ReadAllText(lblFileName.Text);
string[] lines = text.Split('\n');
int total = 0, reduced = 0;
foreach (string line in lines)
{
RawData temp = new RawData(line);
total++;
if (!(temp.Branch.Length == 0 || temp.Branch == "Branch"))
{
reduced++;
data.Add(temp);
}
}
Linq/Entity
foreach (RawData rData in data)
{
tFIManager fimanag;
tBank bank;
tCustomer cust;
fimanag = (context.tFIManagers.Any(fimanager => fimanager.FIName == rData.FinMgrName) ? context.tFIManagers.Where(fimanager => fimanager.FIName == rData.FinMgrName).FirstOrDefault() : context.tFIManagers.Add(new tFIManager { FIName = rData.FinMgrName }));
bank = (context.tBanks.Any(banks => banks.BankName == rData.BankNameFiCat) ? context.tBanks.Where(banks => banks.BankName == rData.BankNameFiCat).FirstOrDefault() : context.tBanks.Add(new tBank { BankName = rData.BankNameFiCat }));
cust = (context.tCustomers.Any(custs => custs.CustomerName == rData.CustName) ? context.tCustomers.Where(custs => custs.CustomerName == rData.CustName).FirstOrDefault() : context.tCustomers.Add(new tCustomer { CustomerName = rData.CustName }));
DateTime DateY4, DealDate, SysDate, JrnlDate;
bool hasDate = DateTime.TryParse(rData.DateY4, out DateY4);
bool hasDeal = DateTime.TryParse(rData.DealDateCat, out DealDate);
bool hasSys = DateTime.TryParse(rData.SysDateCat, out SysDate);
bool hasJrnl = DateTime.TryParse(rData.JrnlDateDv, out JrnlDate);
decimal amt;
bool hasAmt = Decimal.TryParse(rData.Amt, out amt);
tContractsInTransit cit = new tContractsInTransit
{
Branch = rData.Branch,
Pfx = rData.Pfx,
AcctNo = rData.AcctNo,
CustomerID = cust.CustomerID,
CtrlNo = rData.CtrlNo,
RefNo = rData.RefNo,
Days = rData.Days,
DealNoCat = rData.DealNoCat,
BankID = bank.BankID,
FIManagerID = fimanag.FIManagerID,
Desc = rData.Desc,
DealDateCat = null,
SchedNo = rData.SchedNo,
SchedTypeDv = rData.SchedTypeDv,
SchedRemarks = rData.SchedRemarks,
Amt = hasAmt ? amt : 0,
Src = rData.Src,
SysDateCat = null,
JrnlDateDv = null,
DateY4 = null
};
if (hasDeal)
{
cit.DealDateCat = DealDate;
}
if (hasSys)
{
cit.SysDateCat = SysDate;
}
if (hasJrnl)
{
cit.JrnlDateDv = JrnlDate;
}
if (hasDate)
{
cit.DateY4 = DateY4;
}
context.tContractsInTransits.Add(cit);
context.SaveChanges();
}
context.Dispose();
I'm not sure what else to try.. I probably am just tired of looking at it at this point. Thanks in advance!
Just find commas in quotes and replace them prior to doing anything else. You could probably use the code from one of the answers in this question.
Use Microsoft.ACE.OLEDB.12.0 to read Excel file. This should solve your problem.
public static DataSet ReadFile(string file)
{
string connstring = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + file + ";Extended Properties='text;HDR=YES;FMT=Delimited';";
string sql = "select * from " + name;
DataSet ds = null;
Using (OleDbConnection conn = new OleDbConnection(connstring))
{
conn.Open();
using (OleDbDataAdapter myCommand = new OleDbDataAdapter(strSql, connstring))
{
ds = new DataSet();
myCommand.Fill(ds, "table1");
}
}
return ds;
}

Categories

Resources