I'm trying to add multi-selected items to list _AT.SOrderDetails = new List<SOrderDetail>(); but the list is overwritten by the last record selected. The list at right Datagrid only shows data of the last selected record of the left Datagrid instead of all records
foreach (int i in ((GridView)gridControl3.MainView).GetSelectedRows())
{
DataRowView oSOrder = (DataRowView)((GridView)gridControl3.MainView).GetRow(i);
int id = Convert.ToInt32(oSOrder.Row.ItemArray[0]);
if (oSOrder == null)
{
MessageBox.Show("select an item to edit", "Item not yet selected", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
int x = Convert.ToInt32(oSOrder["SOrderID"]);
_Order = db.SOrderTables.FirstOrDefault(o => o.QSOrdersID == x);
SOrderTable oOrder = null;
oOrder = _Order;
if (_Order != null)
{
_AT.SOrderDetails = new List<SOrderDetail>();
if (_Order.SOrderDetails != null)
{
foreach (SOrderDetail oPODItem in _Order.SOrderDetails.ToList())
{
_OrderDetail = new SOrderDetail();
Product oProduct = db.Products.FirstOrDefault(o => o.ProductID == oPODItem.ProductID);
_OrderDetail.ProductID = oPODItem.ProductID;
_OrderDetail.Description = oProduct.Description;
_OrderDetail.Quantity = oPODItem.Quantity;
_OrderDetail.Form = oPODItem.Form;
_OrderDetail.Price = oPODItem.Price;
_AT.SOrderDetails.Add(_OrderDetail);
}
}
}
}
The list at right Datagrid only shows data of the last selected record of the left datagrid
How do I add all values of the selected records, I need help I'm still new, thank you.
i created a new list _tapiwa.SOrderDetails = new List<SOrderDetail>(); So i was now saving information from list _Order.SOrderDetails.ToList(); to the new list i created.
`foreach (int i in ((GridView)gridControl3.MainView).GetSelectedRows())
{
DataRowView oSOrder = (DataRowView)((GridView)gridControl3.MainView).GetRow(i);
int id = Convert.ToInt32(oSOrder.Row.ItemArray[0]);
if (oSOrder == null)
{
MessageBox.Show("select an item to edit", "Item not yet selected", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
int x = Convert.ToInt32(oSOrder["SOrderID"]);
_Order = db.SOrderTables.FirstOrDefault(o => o.QSOrdersID == x);
label1.Text += (oSOrder.Row.ItemArray[0]).ToString()+" "+ (oSOrder.Row.ItemArray[1]).ToString()+" " + (oSOrder.Row.ItemArray[2]).ToString()+ "\n";
SOrderTable oOrder = null;
// db = new MedriveEntities();
oOrder = _Order;
if (_Order != null)
{
if (_tapiwa == null)
{
_tapiwa = new SOrderTable();
_tapiwa.SOrderDetails = new List<SOrderDetail>();
}
foreach (SOrderDetail oPODItem in oOrder.SOrderDetails.ToList())
{
_OrderDetail = new SOrderDetail();
// label2.Text += oPODItem.ProductID.ToString() + " " + oPODItem.Description.ToString() + " " + oPODItem.Quantity.ToString() + "\n";
Product oProduct = db.Products.FirstOrDefault(o => o.ProductID == oPODItem.ProductID);
_OrderDetail.ProductID = oPODItem.ProductID;
_OrderDetail.Description = oProduct.Description;
_OrderDetail.Quantity = oPODItem.Quantity;
_OrderDetail.Form = oPODItem.Form;
_OrderDetail.Price = oPODItem.Price;
_tapiwa.SOrderDetails.Add(_OrderDetail);
}
}
}
RefreshList1();`
Related
I have a large List of objects (over 100k rows in a txt file). I have to do some data work with each item in the list I save the object to the database if it doesnt exist and if it does I increase a number column in the for the item and then update the database while saving the updated item.
If I use a regular foreach loop everything works out fine but it takes over 24 hours to finish.
The issue is that when I use a parallel loop the records do not match and sometimes I will get an error on the .Save() method that the item ID was changed.
THIS CODE WORKS
public List<SreckaIsplacena> UpisiUTabeleSerijski (List<SreckaTemp>srt)
{
_srecke = _glavniRepository.UcitajSamoaktivneSrecke().OrderByDescending(item => item.ID).ToList<Srecka>();
List<SreckaIsplacena> pomList = new List<SreckaIsplacena>();
SreckaIsplacena _isplacena;
foreach (SreckaTemp lt in srt)
{
string beznula = lt.sreIspBroj.TrimStart('0');
SreckeDobici srd = new SreckeDobici();
Srecka sr = (from s in _srecke
where s.Sifra == lt.sreSif && s.Serija == lt.sreSerija
select s).First();
List<SreckeDobici> srDob = _glavniRepository.DohvatiSreckeDobiciZaIsplatniBroj(sr, beznula);
if (srDob.Count == 1)
{
srd = srDob.ElementAt(0);
}
List<SreckaNagrade> sreckaNagrade = new List<SreckaNagrade>(_glavniRepository.DohvatiNagradeZaSrecku(sr.ID).OrderBy(item => item.SifraFox));
double iznos = lt.sreIznDob / lt.sreBrDob;
SreckaNagrade nag = (from sn in sreckaNagrade
where sn.Iznos == lt.sreIznDob
select sn).FirstOrDefault();
Odobrenje odo = new Odobrenje();
odo = odo.DohvatiOdobrenje(valutaGlavna.ID, lt.sreIsplatio).FirstOrDefault();
List<PorezSrecka> listaPoreza = _glavniRepository.UcitajPorezSrecka(valutaGlavna, odo, sr, nag.NagradaId);
List<SreckaIsplacena> sveIsplacene = _glavniRepository.DohvatiIsplaceneSreckeZaValutuIProdavacaSreckuNagraduNovo(valutaGlavna.ID, sr.ID, nag.NagradaId, lt.sreIsplatio);
if (sveIsplacene.Count > 1)
{
System.Windows.MessageBox.Show("Greska, ista srecka s istim dobitkom kod istog prodavaca u istoj valuti 2 put nadjena u bazi");
}
else if (sveIsplacene.Count == 1)
{
_isplacena = sveIsplacene.ElementAt(0);
_isplacena.BrojDobitaka = _isplacena.BrojDobitaka + lt.sreBrDob;
_isplacena.Update();
var index = pomList.FindIndex(r => r.ID == _isplacena.ID);
if (index != -1)
{
pomList[index] = _isplacena;
}
}
else if (sveIsplacene.Count==0)
{
_isplacena = new SreckaIsplacena();
decimal iz = Convert.ToDecimal(lt.sreIznDob);
_isplacena.BrojDobitaka = lt.sreBrDob;
_isplacena.Iznos = iz;
_isplacena.Nagrada = nag;
_isplacena.Prodavac = lt.sreIsplatio;
_isplacena.Valuta = valutaGlavna;
_isplacena.Srecka = sr;
_isplacena.Cijena = Convert.ToDecimal(sr.Cijena);
if (listaPoreza.Count == 1)
{
PorezSrecka ps = listaPoreza.ElementAt(0);
_isplacena.SreckaPorez = ps;
}
_isplacena.Save();
int ispID = _isplacena.ID;
if (ispID != 0)
{
srd.Sre_isplatio = lt.sreIsplatio;
srd.Sre_valuta = valutaGlavna;
srd.Update();
}
pomList.Add(_isplacena);
}
}
return pomList;
}
THIS CODE DOES NOT WORK
public List<SreckaIsplacena> UpisiSamoUTabele(ConcurrentBag<SreckaTemp> srt)
{
_srecke = _glavniRepository.UcitajSamoaktivneSrecke().OrderByDescending(item => item.ID).ToList<Srecka>();
List<SreckaIsplacena> pomList = new List<SreckaIsplacena>();
SreckaIsplacena _isplacena;
Parallel.ForEach(srt, (lt) =>
{
string beznula = lt.sreIspBroj.TrimStart('0');
SreckeDobici srd = new SreckeDobici();
Srecka sr = (from s in _srecke
where s.Sifra == lt.sreSif && s.Serija == lt.sreSerija
select s).First();
List<SreckeDobici> srDob = _glavniRepository.DohvatiSreckeDobiciZaIsplatniBroj(sr, beznula);
if (srDob.Count == 1)
{
srd = srDob.ElementAt(0);
}
List<SreckaNagrade> sreckaNagrade = new List<SreckaNagrade>(_glavniRepository.DohvatiNagradeZaSrecku(sr.ID).OrderBy(item => item.SifraFox));
SreckaNagrade nag = (from sn in sreckaNagrade
where sn.Iznos == lt.sreIznDob
select sn).FirstOrDefault();
Odobrenje odo = new Odobrenje();
odo = odo.DohvatiOdobrenje(valutaGlavna.ID, lt.sreIsplatio).FirstOrDefault();
List<PorezSrecka> listaPoreza = _glavniRepository.UcitajPorezSrecka(valutaGlavna, odo, sr, nag.NagradaId);
List<SreckaIsplacena> sveIsplacene = _glavniRepository.DohvatiIsplaceneSreckeZaValutuIProdavacaSreckuNagraduNovo(valutaGlavna.ID, sr.ID, nag.NagradaId, lt.sreIsplatio);
if (sveIsplacene.Count == 1)
{
_isplacena = sveIsplacene.ElementAt(0);
lock (_isplacena)
{
_isplacena.BrojDobitaka = _isplacena.BrojDobitaka + lt.sreBrDob;
_isplacena.Update();
var index = pomList.FindIndex(r => r.ID == _isplacena.ID);
if (index != -1)
{
pomList[index] = _isplacena;
}
}
}
else if (sveIsplacene.Count==0)
{
_isplacena = new SreckaIsplacena();
decimal iz = Convert.ToDecimal(lt.sreIznDob);
_isplacena.BrojDobitaka = lt.sreBrDob;
_isplacena.Iznos = iz;
_isplacena.Nagrada = nag;
_isplacena.Prodavac = lt.sreIsplatio;
_isplacena.Valuta = valutaGlavna;
_isplacena.Srecka = sr;
_isplacena.Cijena = Convert.ToDecimal(sr.Cijena);
lock(_isplacena)
{
if (listaPoreza.Count == 1)
{
PorezSrecka ps = listaPoreza.ElementAt(0);
_isplacena.SreckaPorez = ps;
}
_isplacena.Save();
int ispID = _isplacena.ID;
if (ispID != 0)
{
srd.Sre_isplatio = lt.sreIsplatio;
srd.Sre_valuta = valutaGlavna;
srd.Update();
}
pomList.Add(_isplacena);
}
}
});
return pomList;
}
I tried using ConcurrentBag instead of List but ran into an issue because ConcurrentBag does not have the FindIndex method (var index = pomList.FindIndex(r => r.ID == _isplacena.ID);). I know there is some way to take out the object and put back in but not sure how to do that and from what I read Lists should be ok if you use locking which I am.
Please help.
I want to create a group of registered clients using different products, categories and sub categories.
I am using asp.net C# and updating database using entity model.
int PID = Convert.ToInt32(ddProduct.SelectedValue);
if (isValidName(txtGroupName.Text))
{
if (ddBusinessCategory.SelectedValue == "0")
{
var clients = db.Client_Master.Where(c => c.InquiredFor == PID).ToList();
foreach (var clt in clients)
{
Group_Master gobj = new Group_Master();
gobj.GName = txtGroupName.Text;
gobj.ProductID = PID;
gobj.CatID = null;
gobj.SubCatID = null;
gobj.ClientID = clt.CID;
gobj.CreatedBy = Convert.ToInt32(((User_Master)Session["User"]).UID);
gobj.CreatedOn = DateTime.Now;
db.Group_Master.AddObject(gobj);
db.SaveChanges();
}
}
else
{
if (ddSubCategory.SelectedValue == "0")
{
int CID = Convert.ToInt32(ddBusinessCategory.SelectedValue);
var clients = db.Client_Master.Where(c => c.InquiredFor == PID && c.BusinessCategory == CID).ToList();
foreach (var clt in clients)
{
Group_Master gobj = new Group_Master();
gobj.GName = txtGroupName.Text;
gobj.ProductID = PID;
gobj.CatID = CID;
gobj.SubCatID = null;
gobj.ClientID = clt.CID;
gobj.CreatedBy = Convert.ToInt32(((User_Master)Session["User"]).UID);
gobj.CreatedOn = DateTime.Now;
db.Group_Master.AddObject(gobj);
db.SaveChanges();
}
}
else
{
int CID = Convert.ToInt32(ddBusinessCategory.SelectedValue);
int SID = Convert.ToInt32(ddSubCategory.SelectedValue);
var clients = db.Client_Master.Where(c => c.InquiredFor == PID && c.BusinessCategory == CID && c.SubCategory == SID).ToList();
foreach (var clt in clients)
{
Group_Master gobj = new Group_Master();
gobj.GName = txtGroupName.Text;
gobj.ProductID = PID;
gobj.CatID = CID;
gobj.SubCatID = SID;
gobj.ClientID = clt.CID;
gobj.CreatedBy = Convert.ToInt32(((User_Master)Session["User"]).UID);
gobj.CreatedOn = DateTime.Now;
db.Group_Master.AddObject(gobj);
db.SaveChanges();
}
}
}
Groups();
}
I tried to add Group ID using many ways but didn't succeed.
Please suggest me how can I solve this.
Thank you !!
You should create new table ClientsProducts, which will have reference to Client ID and Product ID. This is called One-to-Many Relationships.
You can read here about this here.
I Solved this by taking the ID of last data of list and save as a group ID so, with the help of this we get unique group ID.
if (ddBusinessCategory.SelectedValue == "0")
{
var clients = db.Client_Master.Where(c => c.InquiredFor == PID).ToList();
int GrpID = 0;
if (clients.Count() > 0)
{
foreach (var clt in clients)
{
if (ProductGrp(PID, clt.CID))
{
Group_Master gobj = new Group_Master();
gobj.GrpID = 0;
gobj.GName = txtGroupName.Text;
gobj.ProductID = PID;
gobj.CatID = null;
gobj.SubCatID = null;
gobj.ClientID = clt.CID;
gobj.CreatedBy = Convert.ToInt32(((User_Master)Session["User"]).UID);
gobj.CreatedOn = DateTime.Now;
db.Group_Master.AddObject(gobj);
db.SaveChanges();
GrpID = gobj.GID;
}
else
{
ScriptManager.RegisterStartupScript(Page, this.GetType(), "myscript()", "bootbox.alert({title: '<b>Error</b>',message: '<b>Group already exist.</b>',});", true);
break;
}
}
List<Group_Master> ggobj = db.Group_Master.Where(g => g.ProductID == PID && g.CatID == null && g.SubCatID == null).ToList();
foreach (var gid in ggobj)
{
if (gid.GrpID == 0)
{
Group_Master gmobj = db.Group_Master.Single(s => s.GID == gid.GID);
gmobj.GrpID = GrpID;
db.SaveChanges();
}
}
}
else
{
ScriptManager.RegisterStartupScript(Page, this.GetType(), "myscript()", "bootbox.alert({title: '<b>Error</b>',message: '<b>No Clients exist.</b>',});", true);
}
}
I am trying to insert around 5000 records in database using foreach loop. It is taking around 10 min which is not acceptable as per the requirement. I also thought about the approach in which first insert the records in a datatable and then converting it into XML pass it to stored procedure which do the insertion. But unfortunately it is not getting fit in my situation. Now i am doing the same thing using parallel.foreach but after inserting 10 records i am getting "Unique constraint violation for the primary key" error msg. As i am new to parallel programming so not getting the solution for it. Below is my code that i have done so for.
public ActionResult ChannelBulkUpload(HttpPostedFileBase excelFile)
{
bool flag = true;
string path = Server.MapPath("~/Content/UploadFolder/" + excelFile.FileName);
if (System.IO.File.Exists(path))
{
System.IO.File.Delete(path);
}
excelFile.SaveAs(path);
DataTable dt = GetDataTableFromExcel(excelFile, true);
ParallelOptions options = new ParallelOptions
{
MaxDegreeOfParallelism = 4
};
Parallel.ForEach(dt.AsEnumerable(), row =>
{
flag = true;
decimal Key = 0;
string value = "";
decimal channelMstKey = 0;
decimal channelGrpMstKey = 0;
decimal srcFuncKey = 0;
string ExcelMasterChDisplayName = row["MASTER_CHANNEL_DISPLAY_NAME"].ToString();
string ExcelGenreValue = row["GENRE"].ToString();
string ExcelAdsharpValue = row["ADSHARP"].ToString();
string ExcelClusterValue = row["CLUSTER"].ToString();
string ExcelNetworkValue = row["NETWORK"].ToString();
string ExcelBroadCastValue = row["BROADCAST"].ToString();
string ExcelFunctionalAreaname = row["FUNCTIONAL_AREA"].ToString();
string[] Ch_Grp_types = { "GENRE", "ADSHARP", "CLUSTER", "NETWORK", "PLATFORM" };
BarcDataContext bc = new BarcDataContext();
srcFuncKey = bc.REF_SRC_FUNC_AREA.Where(m => m.SRC_FUNC_AREA == ExcelFunctionalAreaname).FirstOrDefault().SRC_FUNC_KEY;
for (int j = 0; j < Ch_Grp_types.Length && flag; j++)
{
if (Ch_Grp_types[j] == "GENRE")
{
Key = 1;
value = ExcelGenreValue;
}
else if (Ch_Grp_types[j] == "NETWORK")
{
Key = 2;
value = ExcelNetworkValue;
}
else if (Ch_Grp_types[j] == "ADSHARP")
{
Key = 3;
value = ExcelAdsharpValue;
}
else if (Ch_Grp_types[j] == "CLUSTER")
{
Key = 4;
value = ExcelClusterValue;
}
else if (Ch_Grp_types[j] == "PLATFORM")
{
Key = 5;
value = ExcelBroadCastValue;
}
DIM_CHANNEL_MST objChMst = bc.DIM_CHANNEL_MST.Where(m => m.CHANNEL_MST_NAME_UPPER == ExcelMasterChDisplayName.ToUpper().Trim()).FirstOrDefault();
if (objChMst == null)
{
flag = false;
}
else
{
if (!string.IsNullOrEmpty(value))
{
var query =
(from A in bc.XREF_CH_GRP_DET_TAG
join B in bc.XREF_CH_GRP_MST_TAG on A.CH_GRP_MST_KEY equals B.CH_GRP_MST_KEY
where A.IS_ACTIVE == "Y" && B.IS_ACTIVE == "Y" && B.CH_GRP_TYPE_KEY == Key && B.CH_GRP_MST_NAME_UPPER == value.ToUpper()
select new XrefChannelGrpDetailTagVM
{
channelGrpDetKey = A.CH_GRP_DET_KEY,
channelGrpMasterNameUpper = B.CH_GRP_MST_NAME_UPPER,
}).Distinct().ToList();
var query2 =
(from A in bc.XREF_CH_GRP_DET_TAG
join B in bc.XREF_CH_GRP_MST_TAG on A.CH_GRP_MST_KEY equals B.CH_GRP_MST_KEY
where A.CHANNEL_MST_KEY == objChMst.CHANNEL_MST_KEY && B.CH_GRP_TYPE_KEY == Key && B.SRC_FUNC_KEY == srcFuncKey
select new XrefChannelGrpDetailTagVM
{
sr_no = A.SR_NO,
channelMstKey = A.CHANNEL_MST_KEY,
channelGrpDetKey = A.CH_GRP_DET_KEY,
channelGrpMstKey = A.CH_GRP_MST_KEY,
srcFuncKey = B.SRC_FUNC_KEY,
channelGrpTypeKey = B.CH_GRP_TYPE_KEY
}).Distinct().ToList();
XREF_CH_GRP_MST_TAG objXrefChGrpMst = bc.XREF_CH_GRP_MST_TAG.Where(m => m.CH_GRP_TYPE_KEY == Key && m.SRC_FUNC_KEY == srcFuncKey && m.CH_GRP_MST_NAME_UPPER == value.ToUpper()).FirstOrDefault();
if (objXrefChGrpMst != null)
{
channelMstKey = objChMst.CHANNEL_MST_KEY;
channelGrpMstKey = objXrefChGrpMst.CH_GRP_MST_KEY;
XREF_CH_GRP_DET_TAG objGrpDetail = new XREF_CH_GRP_DET_TAG();
if (query.Count == 0)
{
objGrpDetail.CH_GRP_DET_KEY = Get_Max_Of_Ch_Grp_Det_Key();
}
else
{
foreach (var detKey in query)
{
if (detKey.channelGrpMasterNameUpper == value.ToUpper())
{
objGrpDetail.CH_GRP_DET_KEY = detKey.channelGrpDetKey;
}
else
{
objGrpDetail.CH_GRP_DET_KEY = Get_Max_Of_Ch_Grp_Det_Key();
}
}
}
if (query2.Count > 0)
{
foreach (var abc in query2)
{
if (abc.channelMstKey == objChMst.CHANNEL_MST_KEY && abc.srcFuncKey == srcFuncKey && abc.channelGrpTypeKey == Key)
{
if (abc.channelGrpDetKey == objGrpDetail.CH_GRP_DET_KEY && abc.channelGrpMstKey == objXrefChGrpMst.CH_GRP_MST_KEY)
{
//Reject
}
else
{
//Update
XREF_CH_GRP_DET_TAG obj = bc.XREF_CH_GRP_DET_TAG.Where(m => m.SR_NO == abc.sr_no).FirstOrDefault();
obj.CH_GRP_DET_KEY = objGrpDetail.CH_GRP_DET_KEY;
obj.CH_GRP_MST_KEY = objXrefChGrpMst.CH_GRP_MST_KEY;
objGrpDetail.CREATE_DATE = DateTime.Now;
objGrpDetail.LAST_UPD_DATE = DateTime.Now;
objGrpDetail.IS_ACTIVE = "Y";
bc.SaveChanges();
}
}
else
{
//Insert
objGrpDetail.CH_GRP_MST_KEY = channelGrpMstKey;
objGrpDetail.CHANNEL_MST_KEY = channelMstKey;
objGrpDetail.SR_NO = Get_Max_Of_XREF_CH_GRP_DET();
objGrpDetail.CREATE_DATE = DateTime.Now;
objGrpDetail.LAST_UPD_DATE = DateTime.Now;
objGrpDetail.IS_ACTIVE = "Y";
bc.XREF_CH_GRP_DET_TAG.Add(objGrpDetail);
bc.SaveChanges();
}
}
}
else
{
objGrpDetail.CH_GRP_MST_KEY = channelGrpMstKey;
objGrpDetail.CHANNEL_MST_KEY = channelMstKey;
objGrpDetail.SR_NO = Get_Max_Of_XREF_CH_GRP_DET();
objGrpDetail.CH_GRP_DET_KEY = objGrpDetail.CH_GRP_DET_KEY;
objGrpDetail.CREATE_DATE = DateTime.Now;
objGrpDetail.LAST_UPD_DATE = DateTime.Now;
objGrpDetail.IS_ACTIVE = "Y";
bc.XREF_CH_GRP_DET_TAG.Add(objGrpDetail);
bc.SaveChanges();
}
}
}
}
}
});
TempData["SuccessMsg"] = "Records uploaded Successfully";
return RedirectToAction("CreateChannel");
}
Getting error when generating the primary key value using the below function :
public static decimal Get_Max_Of_XREF_CH_GRP_DET()
{
try
{
BarcDataContext bc = new BarcDataContext();
return bc.XREF_CH_GRP_DET_TAG.Max(m => m.SR_NO) + 1;
}
catch (Exception e)
{
return 1;
}
}
Where SR_NO is the primary key in that table.
Any help will be very much appreciated. Thanks in advance.
The fastest way to do such inserts is using ADO.NET, specifically, SQL Bulk Insert. If you're using SQL Server as your database, the relevant code will be something like this:
DataTable dt = GetDataTableFromExcel(excelFile, true);
using (var copy = new SqlBulkCopy(yourConnectionString) //There are other overloads too
{
BulkCopyTimeout = 10000,
DestinationTableName = dt.TableName,
})
{
foreach (DataColumn column in dt.Columns)
{
copy.ColumnMappings.Add(column.ColumnName, column.ColumnName);
}
copy.WriteToServer(dt);
}
Please look at my comment to other question
You could use guid as primary key into your table. It would help you to avoid problem with ##IDENTITY. At first you should generate new guid-identity, thank insert the generated value into a row
I have a PivotGrid (DevExpress) within WPF and bind the DataSource to an IList that contains objects of which there are several properties of type DateTime. I want the end-user to choose during runtime which of those DateTime fields the user wants to group by Year, Month, or Day. Is that possible?
I understand that I can provide DateTime groupings programmatically but as there are several DateTime fields it would be quite tedious and unnecessary if the end-user can choose which DateTime field to group and how to group it during runtime.
Can you please guide me how to do that?
I have the following:
<dxdo:LayoutControlItem ItemWidth="1*">
<dxpg:PivotGridControl MaxHeight="800" MaxWidth="800" DataSource="{Binding AllChildOrders}" DataSourceChanged="PivotGridControl_OnDataSourceChanged">
</dxpg:PivotGridControl>
</dxdo:LayoutControlItem>
and in code behind:
private void PivotGridControl_OnDataSourceChanged(object sender, RoutedEventArgs e)
{
var pivotTable = sender as PivotGridControl;
pivotTable.RetrieveFields();
}
The above code works and the pivot table displays all available fields during runtime, including the fields of type DateTime. I do not want to programmatically specify which fields to group in particular ways but let the end-user during runtime choose how and which field to group. Possible?
Alternatively I could imagine to programmatically create sub-groupings as follows: How can I accomplish the following?
0. Pre-generate groups
If you don't want to programmatically specify which fields to group, then you can pregenerate groups for each DateTime field, so user can choose between fields itself and groups of fields.
Here is example:
private void PivotGridControl_DataSourceChanged(object sender, RoutedEventArgs e)
{
var pivotTable = sender as PivotGridControl;
pivotTable.Groups.Clear();
pivotTable.RetrieveFields();
var dateTimeFields = pivotTable.Fields.Where(item => item.DataType == typeof(DateTime)).ToList();
foreach (var field in dateTimeFields)
{
var group = new PivotGridGroup();
group.Add(new PivotGridField() { FieldName = field.FieldName, Caption = field.Caption + " (year)", GroupInterval = FieldGroupInterval.DateYear });
group.Add(new PivotGridField() { FieldName = field.FieldName, Caption = field.Caption + " (month)", GroupInterval = FieldGroupInterval.DateMonth });
group.Add(new PivotGridField() { FieldName = field.FieldName, Caption = field.Caption + " (day)", GroupInterval = FieldGroupInterval.DateDay });
foreach (var groupField in group)
pivotTable.Fields.Add(groupField);
pivotTable.Groups.Add(group);
}
}
Here is screenshot of example:
1. Create sub-groupins
You can create sub-groupings by using PivotGridField.DisplayFolder property.
Here is example:
private void PivotGridControl_DataSourceChanged(object sender, RoutedEventArgs e)
{
var pivotTable = sender as PivotGridControl;
pivotTable.RetrieveFields();
var dateTimeFields = pivotTable.Fields.Where(item => item.DataType == typeof(DateTime)).ToList();
foreach (var field in dateTimeFields)
{
var fieldYear = new PivotGridField()
{
FieldName = field.FieldName,
Caption = field.Caption + " (year)",
GroupInterval = FieldGroupInterval.DateYear,
Visible = false,
DisplayFolder = field.Caption
};
var fieldMonth = new PivotGridField()
{
FieldName = field.FieldName,
Caption = field.Caption + " (month)",
GroupInterval = FieldGroupInterval.DateMonth,
Visible = false,
DisplayFolder = field.Caption
};
var fieldDay = new PivotGridField()
{
FieldName = field.FieldName,
Caption = field.Caption + " (day)",
GroupInterval = FieldGroupInterval.DateDay,
Visible = false,
DisplayFolder = field.Caption
};
pivotTable.Fields.Add(fieldYear);
pivotTable.Fields.Add(fieldMonth);
pivotTable.Fields.Add(fieldDay);
}
}
Here is result:
2. Customize popup menu
You can add commands to field popup menu which allows user to change group interval. For this you can use PivotGridControl.PopupMenuShowing event and PopupMenuShowingEventArgs.Customizations property to customize menu.
Here is example:
private void PivotGridControl_DataSourceChanged(object sender, RoutedEventArgs e)
{
var pivotTable = sender as PivotGridControl;
pivotTable.Groups.Clear();
pivotTable.RetrieveFields();
}
private void PivotGridControl_PopupMenuShowing(object sender, PopupMenuShowingEventArgs e)
{
if (e.MenuType != PivotGridMenuType.Header)
return;
var fieldHeader = e.TargetElement as FieldHeader;
if (fieldHeader == null)
return;
var field = fieldHeader.Content as PivotGridField;
if (field == null || (field.Group != null && field.Group.IndexOf(field) > 0))
return;
var groupInterval = field.GroupInterval;
if (groupInterval == FieldGroupInterval.Default && field.DataType != typeof(DateTime))
return;
var dateTimeIntervals = new List<FieldGroupInterval>(new FieldGroupInterval[]
{
FieldGroupInterval.DateYear,
FieldGroupInterval.DateQuarter,
FieldGroupInterval.DateMonth,
FieldGroupInterval.DateDay,
FieldGroupInterval.Hour,
FieldGroupInterval.Minute,
FieldGroupInterval.Second,
FieldGroupInterval.DateWeekOfYear,
FieldGroupInterval.DateWeekOfMonth,
FieldGroupInterval.DateDayOfYear,
FieldGroupInterval.DateDayOfWeek,
FieldGroupInterval.Date,
FieldGroupInterval.Default
});
if (!dateTimeIntervals.Contains(groupInterval))
return;
var pivotTable = sender as PivotGridControl;
var subMenu = new BarSubItem() { };
subMenu.Content = "Set group interval";
if (field.Group == null)
{
var button = new BarButtonItem() { Content = "Year - Month - Date" };
button.ItemClick += (s, eventArgs) =>
{
pivotTable.BeginUpdate();
var group = field.Tag as PivotGridGroup;
if (group == null)
{
if (groupInterval != FieldGroupInterval.Default)
field.Caption = field.Caption.Replace(" (" + groupInterval + ")", string.Empty);
group = new PivotGridGroup();
group.Add(new PivotGridField() { FieldName = field.FieldName, Caption = field.Caption + " (year)", GroupInterval = FieldGroupInterval.DateYear, Tag = field, Area = field.Area, AreaIndex = field.AreaIndex });
group.Add(new PivotGridField() { FieldName = field.FieldName, Caption = field.Caption + " (month)", GroupInterval = FieldGroupInterval.DateMonth });
group.Add(new PivotGridField() { FieldName = field.FieldName, Caption = field.Caption + " (day)", GroupInterval = FieldGroupInterval.DateDay });
foreach (var groupField in group)
pivotTable.Fields.Add(groupField);
pivotTable.Groups.Add(group);
group.Tag = field;
}
else
{
var yearField = group[0];
yearField.Area = field.Area;
yearField.AreaIndex = field.AreaIndex;
yearField.ShowInCustomizationForm = true;
}
field.Visible = false;
field.ShowInCustomizationForm = false;
pivotTable.EndUpdate();
};
subMenu.Items.Add(button);
}
foreach (var dateTimeInterval in dateTimeIntervals.Where(item => item != groupInterval))
{
var button = new BarButtonItem() { Content = dateTimeInterval, Tag = field };
subMenu.Items.Add(button);
button.ItemClick += (s, eventArgs) =>
{
pivotTable.BeginUpdate();
var group = field.Group;
if (group != null)
{
var yearField = field;
field = yearField.Tag as PivotGridField;
field.Area = yearField.Area;
field.AreaIndex = yearField.AreaIndex;
field.ShowInCustomizationForm = true;
yearField.Visible = false;
yearField.ShowInCustomizationForm = false;
}
else if (groupInterval != FieldGroupInterval.Default)
field.Caption = field.Caption.Replace(" (" + groupInterval + ")", string.Empty);
field.GroupInterval = dateTimeInterval;
if (dateTimeInterval != FieldGroupInterval.Default)
field.Caption += " (" + dateTimeInterval + ")";
pivotTable.EndUpdate();
};
}
e.Customizations.Add(subMenu);
}
Here is result:
Look at the following code example.
What it does:
Iterates a bunch of customers. If it already knows the customer, it retrieves the existing database object for that customer (this is the problem-ridden part). Otherwise, it creates a new object (this works fine).
All loans where the social security number matches (CPR) will be added to the new or existing customer.
The problem: it works for new customer objects, but when I retrieve an existing customer object, the loans lose their relation to the customer when saved (CustomerID = null). They are still saved to the database.
Any ideas?
protected void BuildCustomerData()
{
Console.WriteLine(" Starting the customer build.");
var counter = 0;
var recycleCount = 100;
var reportingCount = 100;
var sTime = DateTime.Now;
var q = from c in db.IntermediaryRkos
select c.CPR;
var distincts = q.Distinct().ToArray();
var numbersToProcess = distincts.Count();
Console.WriteLine(" Identified " + numbersToProcess + " customers. " + (DateTime.Now - sTime).TotalSeconds);
foreach (var item in distincts)
{
var loans = from c in db.IntermediaryRkos
where c.CPR == item
select c;
var existing = db.Customers.Where(x => x.CPR == item).FirstOrDefault();
if (existing != null)
{
this.GenerateLoanListFor(existing, loans);
db.Entry(existing).State = System.Data.EntityState.Modified;
}
else
{
var customer = new Customer
{
CPR = item,
};
this.GenerateLoanListFor(customer, loans);
db.Customers.Add(customer);
db.Entry(customer).State = System.Data.EntityState.Added;
}
counter++;
if (counter % recycleCount == 0)
{
this.SaveAndRecycleContext();
}
if (counter % reportingCount == 0)
{
Console.WriteLine(" Processed " + counter + " customers of " + numbersToProcess + ".");
}
}
db.SaveChanges();
}
protected void GenerateLoanListFor(Customer customer, IQueryable<IntermediaryRko> loans)
{
customer.Loans = new List<Loan>();
foreach (var item in loans.Where(x => x.DebtPrefix == "SomeCategory").ToList())
{
var transformed = StudentLoanMap.CreateFrom(item);
customer.Loans.Add(transformed);
db.Entry(transformed).State = System.Data.EntityState.Added;
}
}
EDIT 1:
As pointed out, I am manually setting the state. This is due to the RecycleContext call, which is implemented for maximum db transaction performance:
protected void SaveAndRecycleContext()
{
db.SaveChanges();
db.Dispose();
db = new SolutionDatabase();
db.Configuration.AutoDetectChangesEnabled = false;
db.Configuration.ValidateOnSaveEnabled = false;
}
Existing loan or not, you wipe out the customer.Loans Property when you call
customer.Loans = new List<Loan>();