ASP NET MVC Core 2 with entity framework saving primery key Id to column that isnt a relationship column - foreign-keys

Please look at this case:
if (product.ProductId == 0)
{
product.CreateDate = DateTime.UtcNow;
product.EditDate = DateTime.UtcNow;
context.Products.Add(product);
if (!string.IsNullOrEmpty(product.ProductValueProduct)) { SaveProductValueProduct(product); }
}
context.SaveChanges();
When I debug code the ProductId is negative, but afer save the ProductId is corect in database (I know this is normal), but when I want to use it here: SaveProductValueProduct(product) after add to context.Products.Add(product); ProductId behaves strangely. (I'm creating List inside SaveProductValueProduct)
List<ProductValueProductHelper> pvpListToSave = new List<ProductValueProductHelper>();
foreach (var item in dProductValueToSave)
{
ProductValueProductHelper pvp = new ProductValueProductHelper();
pvp.ProductId = (item.Value.HasValue ? item.Value : product.ProductId).GetValueOrDefault();
pvp.ValueId = Convert.ToInt32(item.Key.Remove(item.Key.IndexOf(",")));
pvp.ParentProductId = (item.Value.HasValue ? product.ProductId : item.Value);
pvpListToSave.Add(pvp);
}
I want to use ProductId for relationship. Depends on logic I have to save ProductId at ProductId column OR ProductId at ParentProductId column.
The ProductId 45 save corent at ProductId column (3rd row - this is a relationship), BUT not at ParentProductId (2nd row - this is just null able int column for app logic), although while debug I pass the same negative value from product.ProductId there.
QUESTION:
how can I pass correct ProductId to column that it isn't a relationship column

I just use SaveProductValueProduct(product) after SaveChanges (used SaveChanges twice)
if (product.ProductId == 0)
{
product.CreateDate = DateTime.UtcNow;
product.EditDate = DateTime.UtcNow;
context.Products.Add(product);
}
context.SaveChanges();
if (product.ProductId != 0)
{
if (!string.IsNullOrEmpty(product.ProductValueProduct)) { SaveProductValueProduct(product); }
context.SaveChanges();
}
I set this as an answer because it fixes the matter, but I am very curious if there is any other way to solve this problem. I dont like to use context.SaveChanges(); one after another.

Related

Acumatica GI - Inventory Transaction History Screen

I want to create a GI for Inventory Transaction History Screen (IN405000).
Since the table InventoryTranHistEnqResult isn't present in the database...few of the columns of this screen are taken from INTran Table.
I am not able to find following columns: BegQty, QtyIn, QtyOut, EndQty...
I also tried the following query on database to find these columns
SELECT c.name AS ColName, t.name AS TableName
FROM sys.columns c
JOIN sys.tables t ON c.object_id = t.object_id
WHERE c.name LIKE '%EndQty%'
The DAC for these fields is:
enter image description here
Looking at the information behind the page in the page Graph will give you the answers to your question. Inventory Transaction History Screen (IN405000) uses graph InventoryTranHistEnq. The grid in this page uses DAC InventoryTranHistEnqResult in the following view:
PXSelectJoin<InventoryTranHistEnqResult,
CrossJoin<INTran>,
Where<True, Equal<True>>,
OrderBy<Asc<InventoryTranHistEnqResult.gridLineNbr>>> ResultRecords
The ResultsRecords are built dynamically in the inquiry using the following:
protected virtual IEnumerable resultRecords()
{
int startRow = PXView.StartRow;
int totalRows = 0;
decimal? beginQty = null;
List<object> list = InternalResultRecords.View.Select(PXView.Currents, PXView.Parameters, new object[PXView.SortColumns.Length], PXView.SortColumns, PXView.Descendings, PXView.Filters, ref startRow, PXView.MaximumRows, ref totalRows);
PXView.StartRow = 0;
foreach (PXResult<InventoryTranHistEnqResult> item in list)
{
InventoryTranHistEnqResult it = (InventoryTranHistEnqResult)item;
it.BegQty = beginQty = (beginQty ?? it.BegQty);
decimal? QtyIn = it.QtyIn;
decimal? QtyOut = it.QtyOut;
beginQty += (QtyIn ?? 0m) - (QtyOut ?? 0m);
it.EndQty = beginQty;
}
return list;
}
So i guess the short answer is you cannot use the results of this page for a GI as it is built in the page only. You might want to look into adding what you need to this history page via a customization or make your own version of this page/graph/dac if the information you need is that important.

IcCube - Treemap Chart with duplicate names

In the Google Treemap Chart every node has to have a unique id, but two nodes can have the same name (https://groups.google.com/d/msg/google-visualization-api/UDLD-a-0PCM/IwVCGzsWOg8J).
I used the schema from the parent/child demo (http://www.iccube.com/support/documentation/user_guide/schemas_cubes/dim_parentchild.php)
Using the following MDX statement in the treemap works, as long as the names of the nodes are unique:
WITH
MEMBER [parent_name] as IIF( [dim (ALL)].[Hierarchy].currentmember
is [dim (ALL)].[Hierarchy].[ALL],'',
[dim (ALL)]. [Hierarchy].currentmember.parent.name )
SELECT
{[parent_name],[Measures].[value]} on 0,
non empty [dim (ALL)].[Hierarchy].members on 1
FROM
[Cube]
If I added the line to the In-memory table in icCube's schema :
7,4,Spain, 2, 32
but the name Spain is double when rendering the Treemap. To support names a child definition in the GVI table should be something like this:
{v:'uniqueID-Spain', f:'Spain'}
As a workaround you can use the following code that modifies GviTable processing for the google tree widget. Check the example here:
https://drive.google.com/file/d/0B3kSph_LgXizSVhvSm15Q1hIdW8/view?usp=sharing
Report JavaScript:
function consumeEvent( context, event ) {
if (event.name == 'ic3-report-init') {
if(!_.isFunction(ic3.originalProcessGviTable)) {
ic3.originalProcessGviTable = viz.charts.GenericGoogleWidget.prototype.processGviTable
}
viz.charts.GenericGoogleWidget.prototype.processGviTable = function(gviTable){
if(this.props.ic3chartType === "TreeMap") {
gviTable = gviTable || this.gviTable();
var underlying = _.cloneDeep(gviTable.getUnderlyingGviTable());
_.each(underlying.rows, function(row){
// Replace id with parent prefixed
if(_.isObject(row.c[0]) && !_.isString(row.c[0].f)) {
row.c[0].f = row.c[0].v;
if(_.isObject(row.c[0].p) && _.isString(row.c[0].p.mun)) {
row.c[0].v = row.c[0].p.mun;
}
}
});
gviTable = viz.GviTable.fromSnapshot(underlying);
this.startColumnSelection = gviTable.getNumberOfHeaderColumns() - 1;
return viz.charts.toGoogleDataTableOneRowHeader(gviTable);
} else {
return ic3.originalProcessGviTable.apply(this, gviTable);
}
}
}
}
For the query like:
WITH
MEMBER [parent_name] as
IIF( [dim (ALL)].[Hierarchy].currentmember.isAll(),
'',
([dim (ALL)].[Hierarchy].currentmember.parent.uniqueName)
)
SELECT
{[parent_name],[Measures].[value]} on 0,
non empty [dim (ALL)].[Hierarchy].members on 1
FROM
[Cube]
This is a limitation of Google Treemap chart that is using the same column for the id and the label. Besides changing the names to ensure they are unique (e.g. adding the parent) I don't see a workaround to this.
An option would be using another Treemap chart (e.g. one from D3) that has not this limitation.
--- icCube Schema ---
The schema is working (just use , instead of ; as separator )
--- icCube Reporting ---
The issue using Treemap is that you've two rows with the same id (Germany), fiddle
This fiddle is a running example of treemap

How do I query multiple IDs via the ContentSearchManager?

When I have an array of Sitecore IDs, for example TargetIDs from a MultilistField, how can I query the ContentSearchManager to return all the SearchResultItem objects?
I have tried the following which gives an "Only constant arguments is supported." error.
using (var s = Sitecore.ContentSearch.ContentSearchManager.GetIndex("sitecore_master_index").CreateSearchContext())
{
rpt.DataSource = s.GetQueryable<SearchResultItem>().Where(x => f.TargetIDs.Contains(x.ItemId));
rpt.DataBind();
}
I suppose I could build up the Linq query manually with multiple OR queries. Is there a way I can use Sitecore.ContentSearch.Utilities.LinqHelper to build the query for me?
Assuming I got this technique to work, is it worth using it for only, say, 10 items? I'm just starting my first Sitecore 7 project and I have it in mind that I want to use the index as much as possible.
Finally, does the Page Editor support editing fields somehow with a SearchResultItem as the source?
Update 1
I wrote this function which utilises the predicate builder as dunston suggests. I don't know yet if this is actually worth using (instead of Items).
public static List<T> GetSearchResultItemsByIDs<T>(ID[] ids, bool mustHaveUrl = true)
where T : Sitecore.ContentSearch.SearchTypes.SearchResultItem, new()
{
Assert.IsNotNull(ids, "ids");
if (!ids.Any())
{
return new List<T>();
}
using (var s = Sitecore.ContentSearch.ContentSearchManager.GetIndex("sitecore_master_index").CreateSearchContext())
{
var predicate = PredicateBuilder.True<T>();
predicate = ids.Aggregate(predicate, (current, id) => current.Or(p => p.ItemId == id));
var results = s.GetQueryable<T>().Where(predicate).ToDictionary(x => x.ItemId);
var query = from id in ids
let item = results.ContainsKey(id) ? results[id] : null
where item != null && (!mustHaveUrl || item.Url != null)
select item;
return query.ToList();
}
}
It forces the results to be in the same order as supplied in the IDs array, which in my case is important. (If anybody knows a better way of doing this, would love to know).
It also, by default, ensures that the Item has a URL.
My main code then becomes:
var f = (Sitecore.Data.Fields.MultilistField) rootItem.Fields["Main navigation links"];
rpt.DataSource = ContentSearchHelper.GetSearchResultItemsByIDs<SearchResultItem>(f.TargetIDs);
rpt.DataBind();
I'm still curious how the Page Editor copes with SearchResultItem or POCOs in general (my second question), am going to continue researching that now.
Thanks for reading,
Steve
You need to use the predicate builder to create multiple OR queries, or AND queries.
The code below should work.
using (var s = Sitecore.ContentSearch.ContentSearchManager.GetIndex("sitecore_master_index").CreateSearchContext())
{
var predicate = PredicateBuilder.True<SearchResultItem>();
foreach (var targetId in f.Targetids)
{
var tempTargetId = targetId;
predicate = predicate.Or(x => x.ItemId == tempTargetId)
}
rpt.DataSource = s.GetQueryable<SearchResultItem>().Where(predicate);
rpt.DataBind();
}

Faceted search on multilist in sitecore 7

I'm able to generate the facet and bind the result in Linkbutton within repeater control. Now I'm facing problem in generating the facet query with OR operator when the user selects more than 1 value of same facet type in Sitecore 7.
What can be done to solve it?
Thanks
Here's a blog post about solving this using PredicateBuilder with a specific code example:
http://www.nttdatasitecore.com/en/Blog/2013/November/Building-Facet-Queries-with-PredicateBuilder.aspx
To implement the Facet search in Sitecore use PredicateBuilder class to build the filter query and then add the filter query to the base query. Code is mentioned below:
List<PeopleFields> objPeoplefields = new List<PeopleFields>();
IQueryable<PeopleFields> Query = null;
var predicatePractice = Sitecore.ContentSearch.Utilities.PredicateBuilder.False<PeopleFields>();
var predicateOffice = Sitecore.ContentSearch.Utilities.PredicateBuilder.False<PeopleFields>();
using (var context = ContentSearchManager.GetIndex(SITECORE_WEB_INDEX).CreateSearchContext())
{
//Base query
Query = context.GetQueryable<PeopleFields>().Where(i => i.FirstName.StartsWith(txtFirstName.Text)).Where(i => i.LastName.StartsWith(txtLastName.Text));
foreach (string strselecteFacet in lstPracticefacetSelected)
{
//filter query
predicatePractice = predicatePractice.Or(x => x.Practice.Like(strselecteFacet));
}
foreach (string strselecteFacet in lstOfficefacetSelected)
{
//Filter query
predicateOffice = predicateOffice.Or(x => x.Office.Like(strselecteFacet));
}
//Joining the filter query alongwith base query
if (lstPracticefacetSelected.Count > 0 && lstOfficefacetSelected.Count > 0)
Query = Query.Filter(predicatePractice).Filter(predicateOffice);
else if (lstPracticefacetSelected.Count > 0 && lstOfficefacetSelected.Count == 0)
Query = Query.Filter(predicatePractice);
else if (lstPracticefacetSelected.Count == 0 && lstOfficefacetSelected.Count > 0)
Query = Query.Filter(predicateOffice);
objPeoplefields = Query.ToList();
}
As a quick way, if you're ok with having SitecoreUISearchResultItem as the query result type, you may be able to utilize the same method Sitecore 7 uses to parse queries entered in the content editor search:
Sitecore.Buckets.Util.UIFilterHelpers.ParseDatasourceString(string query)
If that's not up to what you're after, reading how it's implemented with a decompiler (ILSpy, DotPeek, Reflector, Resharper, etc) may help you in composing an expression manually based on dynamic criteria.

Hide UltragridRow that has no visible child rows after applying RowFilter

So, I am setting the DataSource of my BindingSource to the DefaultViewManager of a DataSet that has a DataRelation. I then set my BindingSource as the UltraGrid's DataSource before applying a RowFilter to the the "SalesOrderSublines" DataView.
public void RefreshData()
{
var dataset = DataService.GetMillWorkOrders()
bindingSource1.DataSource = dataset.DefaultViewManager;
ultraGridSequences.SetDataBinding(bindingSource1, "", true, true);
var dvm = bindingSource1.DataSource as DataViewManager;
dvm.DataViewSettings["SalesOrderSublines"].RowFilter = "LINE_NO = 2;
}
public static DataSet GetMillWorkOrders()
{
DataSet ds = OracleHelper.ExecuteDataset(_connectionString, CommandType.StoredProcedure, SQL.GET_WORK_ORDERS);
ds.Tables[0].TableName = "WorkOrders";
ds.Tables[1].TableName = "SalesOrderSublines";
var dr = new DataRelation("WorkOrderSublines", ds.Tables["WorkOrders"].Columns["WORK_ORDER"], ds.Tables["SalesOrderSublines"].Columns["WORK_ORDER"]);
ds.Relations.Add(dr);
return ds;
}
Then, as the UltraGridRows are initializing I want to hide any parent row ("WorkOrders") that has no visible child rows ("WorkOrderSublines") because of my RowFilter.
private void ultraGridSequences_InitializeRow(object sender, Infragistics.Win.UltraWinGrid.InitializeRowEventArgs e)
{
if (e.Row.Band.Key != "WorkOrders") return;
e.Row.Hidden = e.Row.ChildBands["WorkOrderSublines"].Rows.VisibleRowCount == 0;
}
Although the RowFilter does work properly on the rows in the "WorkOrderSublines" band the VisibleRowCount of the band is still greater than zero and so the parent row is never hidden. My guess is that I want to look for something other than the VisibleRowCount of the ChildBand to determine if the top-level row should be hidden, but I'm stuck. Any help would be greatly appreciated. Thanks ahead of time.
Instead of relying on VisibleRowCount you could simply compare the count of child row filtered vs total count.
void ultraGridSequences_InitializeRow(object sender, Infragistics.Win.UltraWinGrid.InitializeRowEventArgs e)
{
if (e.Row.Band.Key != "WorkOrders") return;
var sublinesBand = e.Row.ChildBands["WorkOrderSublines"]
e.Row.Hidden = sublinesBand.Rows.Count(row => row.IsFilteredOut) ==
sublinesBand.Rows.Count();
}
Should be fine performance-wise so long as we're not talking huge amounts of records?
Using the Filtering within the Grid may be an option rather than using the filtering in the DataSource. The following resources have more details on implementing this:
http://forums.infragistics.com/forums/t/51892.aspx
http://devcenter.infragistics.com/Support/KnowledgeBaseArticle.aspx?ArticleID=7703