Remove an IObservable from merged sequence - wpf

I am using Observable.Merge to combine multiple sequences and display in a single view in UI. Users can choose to add or remove sequences(feeds) in the UI. While I have used Merge to combine feeds. I am not sure how I can detach an IObservable from a Merged sequence. Currently I am creating a brand new IObservable omitting the feeds I want to. Is it possible to dynamically add and remove to an IObsevable that the ViewModel has already subscribed to?

Take a look at using IObservable<IObservable<T>> and then use Merge. This automatically allows you to remove a sequence by ending the inner IObservable<T>. Simple.

Something like this would also work, but I suspect there are neater ways.
class Merger<T>
{
Subject<T> _merged = new Subject<T>();
public IObservable<T> Merged { get { return _merged; } }
public IDisposable Add(IObservable<T> newStream)
{
return newStream.Subscribe(_merged);
}
}
To remove something from the merged stream, dispose of the IDisposable.

This might help get you started, but on reconnection, because b is cold, b will restart from the beginning:
var a = Observable.Generate('A', x => x <= Char.MaxValue, x => ++x, x => x, x => TimeSpan.FromMilliseconds(200)).Select(x => "a: " + x).Publish();
var b = Observable.Generate('a', x => x <= Char.MaxValue, x => ++x, x => x, x => TimeSpan.FromMilliseconds(500)).Select(x => "b: " + x).Publish();
var merged = a.Merge(b).Publish();
var submerged = merged.Subscribe(x => x.Dump());
var subA = a.Connect();
var subB = b.Connect();
merged.Connect();
Task.Delay(2000).ContinueWith(t => subB.Dump("Disposing b.").Dispose());
Task.Delay(4000).ContinueWith(t => b.Connect()).ContinueWith(_ => "Reconnected to b");
EDIT:
To add another 'c' to the merged IO:
var a = Observable.Generate('A', x => x <= Char.MaxValue, x => ++x, x => x, x => TimeSpan.FromMilliseconds(200)).Select(x => "a: " + x).Publish();
var b = Observable.Generate('a', x => x <= Char.MaxValue, x => ++x, x => x, x => TimeSpan.FromMilliseconds(500)).Select(x => "b: " + x).Publish();
var c = Observable.Generate('1', x => x <= Char.MaxValue, x => ++x, x => x, x => TimeSpan.FromMilliseconds(100)).Select(x => "c: " + x).Publish();
var merged = a.Merge(b).Merge(c).Publish();
var submerged = merged.Subscribe(x => x.Dump());
var subA = a.Connect();
var subB = b.Connect();
merged.Connect();
Task.Delay(2000).ContinueWith(t => subB.Dump("Disposing b.").Dispose());
Task.Delay(4000).ContinueWith(t => b.Connect()).ContinueWith(_ => "Reconnected to b".Dump());
Task.Delay(6000).ContinueWith(t => c.Connect()).ContinueWith(_ => "Connecting to c".Dump());

Related

Run connectedComponents of GraphX with the same data and code twice,the result is different

When I run connectedComponents of GraphX with the same data and code twice,the result is different,why?
Here's my code:
val edgeDF = sql("select * from fkdm.fkdm_fk_base_sna_bm_edge_s_d").rdd
val edgePair = edgeDF.map{ line =>
val v1 = line.getString(0)
val v2 = line.getString(1)
(v1,v2)
}
val vertices = edgePair.map(line => line._1).union(edgePair.map(line =>
line._2)).distinct()
val verticesUniqueId = vertices.zipWithUniqueId()
val edge_numberic = edgePair.join(verticesUniqueId).map(line =>
(line._2._1,line._2._2)).join(verticesUniqueId).map(line =>
(line._2._1,line._2._2))
val vertice_rdd = verticesUniqueId.map{line =>
(line._2.toLong,line._1)
}
val edge_rdd = edge_numberic.map{line =>
Edge(line._1,line._2,1)
}
val graph = Graph(vertice_rdd,edge_rdd)
val cc = graph.connectedComponents()
val ccDF = cc.vertices.map(x =>
ComponentsGraph(x._1.toString,x._2.toString)).toDF()
ccDF.createOrReplaceTempView("temp_ccDF")
sql("drop table if exists buming.buming_sna_vertices_groupnum ")
sql("CREATE TABLE buming.buming_sna_vertices_groupnum AS SELECT * FROM
temp_ccDF")
I found the number of vertices in the largest group is diffent.

Covert Collection of Objects to Collection of Dictionary<string, object>

I'm fetching a large Amount of data from RIA Service. the return type have group of objects like RouteA, HistroyRouteA. HistroyLogRouteA all have records for different years with same Unique Key.
I have to Bind this data dynamically to a RadGridView. Always I have unknown columns in result.
For this I followed
http://blogs.telerik.com/vladimirenchev/posts/11-09-28/dynamic-binding-for-your-silverlight-applications.aspx
http://www.telerik.com/forums/rowdetailstemplate-binding-with-dynamic-data
And build My data Collection with Code :
private void OnShowPreviousYear(object parameter)
{
GridViewHeaderCell cell = parameter as GridViewHeaderCell;
var head = cell.Column.Header;
this.context.Load<Route>(this.context.GetRoutesQuery(), LoadBehavior.MergeIntoCurrent, OnRouteHistoryLoadComplete, null);
}
private void OnRouteHistoryLoadComplete(LoadOperation<Route> lo)
{
object ro = null;
if (lo.Entities != null)
{
this.context.Load<Routeshistory>(this.context.GetRouteshistoriesQuery(), LoadBehavior.MergeIntoCurrent, (lp) =>
{
Route recent = lo.Entities.FirstOrDefault();
int year =(int)recent.Hpmsyear-1;
var rows = this.context.Routes.Join(this.context.Routeshistories,
r => r.Routeid.ToString(),
h => h.Routeid.ToString(),
(r, h) => new { r, h });//.Where(t => t.r.Routeid == t.h.Routeid );
RoutesGridData = new ObservableCollection<DataRow>();
int count = 0;
foreach (var tmpR in rows)
{
//Debug.WriteLine(tmpR.r.Routeid + " -- " + tmpR.h.Routeid);
if (count < 50)
{
DataRow row = new DataRow();
if (tmpR.r is Route)
{
Type type = tmpR.r.GetType();
foreach (PropertyInfo info in type.GetProperties())
{
// Debug.WriteLine(info.Name + "--- NAME OF PRR");
var val = info.GetValue(tmpR.r, null);
if (!info.Name.Equals("EntityConflict")
&& !info.Name.Equals("ValidationErrors")
&& !info.Name.Equals("HasValidationErrors")
&& !info.Name.Equals("EntityState")
&& !info.Name.Equals("HasChanges")
&& !info.Name.Equals("IsReadOnly")
&& !info.Name.Equals("EntityActions"))
{
row[info.Name] = val;
}
}
}
// other tables...
RoutesGridData.Add(row);
}
count++;
}
}, null);
}
// var b = ro;
}
this code works fine for small record like 50 rows. but I when It try to convert all data it become slow. and screen crashes. I think this is because of Reflection. Is there any other way to convert my fetch data into Dictionary? Means I can map my table to dictionary in Entity Framework or Linq can do this for me without getting my code slow etc.
My Entities are mapped with EF 6 & I m using Deart oracle connector.
Due to reflection it was getting extremely slow so I did in during Linq query it's working for a while what data I have with me.
var rowss = this.context.Routes.Join(this.context.Routeshistories,
r => r.Routeid,
h => h.Routeid,
(r, h) => new DataRow(
(from x in r.GetType().GetProperties() select x).Where(x => x.Name != "EntityConflict"
&& x.Name != "ValidationErrors"
&& x.Name != "HasValidationErrors"
&& x.Name != "HasChanges"
&& x.Name != "EntityState"
&& x.Name != "IsReadOnly"
&& x.Name != "EntityActions")
.ToDictionary(x => x.Name, x => (x.GetGetMethod().Invoke(r, null) == null ? "" : x.GetGetMethod().Invoke(r, null))),
(from x in h.GetType().GetProperties() select x).Where(x => x.Name == head)
.ToDictionary(x => x.Name + "-" + year.ToString(), x => (x.GetGetMethod().Invoke(h, null) == null ? "" : x.GetGetMethod().Invoke(h, null))))
);// , new EqualityComparerString()
RoutesGridData = new ObservableCollection<DataRow>(rowss);

Sum of multiple queries to optimise number of queries performed

I have a query which must sum the values from several tables and add the result. The system is simply an inventory system and I'm trying to get the stock level by calculating incomings (deliveries), outgoings (issues) and adjustments to items.
As the stock level is a calculated value (sum(deliveries) - sum(issues)) + sum(adjustments) I am trying to create a function that will get this value with a minimal number of queries.
At current I have linq that performs three separate queries to get each summed value and then perform the addition/subtraction in my function, however I am convinced there must be a better way to calculate the value without having to do three separate queries.
The current function is as follows:
public static int GetStockLevel(int itemId)
{
using (var db = EntityModel.Create())
{
var issueItemStock = db.IssueItems.Where(x => x.ItemId == itemId).Sum(x => x.QuantityFulfilled);
var deliveryItemStock = db.DeliveryItems.Where(x => x.ItemId == itemId).Sum(x => x.Quantity);
var adjustmentsStock = db.Adjustments.Where(x => x.ItemId == itemId).Sum(x => x.Quantity);
return (deliveryItemStock - issueItemStock) + adjustmentsStock;
}
}
In my mind the SQL query is quite simple, so I have considered a stored procedure, however I think there must be a way to do this with linq.
Many thanks
Edit: Answer
Taking the code from Ocelot20's answer, with a slight change. Each of the lets can return a null, and if it does then linq throws an exception. Using the DefaultIfEmpty command will negate this, and return a 0 for the final calculation. The actual code I have used is as follows:
from ii in db.Items
let issueItems = db.IssueItems.Where(x => x.ItemId == itemId).Select(t => t.QuantityFulfilled).DefaultIfEmpty(0).Sum()
let deliveryItemStock = db.DeliveryItems.Where(x => x.ItemId == itemId).Select(t => t.Quantity).DefaultIfEmpty(0).Sum()
let adjustmentsStock = db.Adjustments.Where(x => x.ItemId == itemId).Select(t => t.Quantity).DefaultIfEmpty(0).Sum()
select (deliveryItemStock - issueItems) + adjustmentsStock);
Without knowing what your entities look like, you could do something like this:
public static int GetStockLevel(int itemId)
{
using (var db = EntityModel.Create())
{
// Note: Won't work if there are no IssueItems found.
return (from ii in db.IssueItems
let issueItems = db.IssueItems.Where(x => x.ItemId == itemId)
.Sum(x => x.QuantityFulfilled)
let deliveryItemStock = db.DeliveryItems.Where(x => x.ItemId == itemId)
.Sum(x => x.Quantity)
let adjustmentsStock = db.Adjustments.Where(x => x.ItemId == itemId)
.Sum(x => x.Quantity)
select issueItems + deliveryItemStock + adjustmentsStock).FirstOrDefault() ?? 0;
}
}
I tested a similar query on my own db and it worked in a single query. I suspect that since they all have a common ItemId, that using entity relations could make this look something like:
// Ideal solution:
(from i in db.Items
where i.Id == itemId
let issueItems = i.IssueItems.Sum(x => x.QuantityFulfilled)
let deliveryItemStock = i.DeliveryItems.Sum(x => x.Quantity)
let adjustmentsStock = i.Adjustments.Sum(x => x.Quantity)
select issueItems + deliveryItemStock + adjustmentsStock).SingleOrDefault() ?? 0;
Have you considered adding a view to the database that performs the calculations that you can then just use a simple select query (or SP) to return the values that you need?
I reckon this should work and the SQL generated is not particularly complex. If you think there is something wrong with it let me know and I will update my answer.
public static int GetStockLevel(int itemId)
{
using (var db = EntityModel.Create())
{
return db.IssueItems.Where(x => x.ItemId == itemId).GroupBy(x => x.ItemId)
.GroupJoin(db.DeliveryItems, x => x.First().ItemId, y => y.ItemId, (x, y) => new
{ Issues = x, Deliveries = y})
.GroupJoin(db.Adjustments, x=> x.Issues.First().ItemId, y=> y.ItemId, (x, y) => new
{
IssuesSum = x.Issues.Sum(i => i.QuantityFullfilled),
DeliveriesSum = x.Deliveries.Sum(d => d.Quantity),
AdjustmentsSum = y.Sum(a => a.Quantity)})
.Select(x => x.IssuesSum - x.DeliverysSum + x.AdjustmentsSum);
}
}

How to group by and order by, with LINQ, NHibernate and uNHAddins

We're building a WPF application, using Oracle database, also using NHibernate and uNHAddins extensions. In a DataGrid, we're trying to get values from a table, with this query LINQ:
return (from f in rFConsumption.GetAll()
let d = f.CounterDtm
where f.CounterDtm >= dataHoraInicio && f.CounterDtm <= dataHoraFim
group f by (d.Year - 2000) * 384 + d.Month * 32 + d.Day into g
select new RFConsumption
{
COGCounter1 = (g.Sum(f => f.COGCounter1)),
BFCounter1 = (g.Sum(f => f.BFCounter1)),
NatGasCounter1 = (g.Sum(f => f.NatGasCounter1)),
MixGasCounter1 = (g.Sum(f => f.MixGasCounter1)),
COGCounter2 = (g.Sum(f => f.COGCounter2)),
BFCounter2 = (g.Sum(f => f.BFCounter2)),
NatGasCounter2 = (g.Sum(f => f.NatGasCounter2)),
MixGasCounter2 = (g.Sum(f => f.MixGasCounter2)),
COGCounter3 = (g.Sum(f => f.COGCounter3)),
BFCounter3 = (g.Sum(f => f.BFCounter3)),
NatGasCounter3 = (g.Sum(f => f.NatGasCounter3)),
MixGasCounter3 = (g.Sum(f => f.MixGasCounter3)),
}
).ToList<RFConsumption>();
So, my question is:
How I do to use group by, with order by, using NHibernate;
How can i make group by return date data field to that specified group.
You can write the same query with NHibernate with several ways, the most interesting one for me really is the NHibernate QueryOver<>.
So, if your query works fine then, this query should work:
return Session.QueryOver<rFConsumption>()
.Where( fc => (fc.CounterDtm >= dataHoraInicio && fc.CounterDtm <= dataHoraFim))
.SelectList(list => list
.SelectGroup(f => ((f.CounterDtm.Year - 2000) * 384 + f.CounterDtm.Month * 32 + f.CounterDtm.Day)) //use group by
.Select(exp =>
new RFConsumption() //here you define the return data type based on your specified group
{
// exp[0] represents the data returned and grouped by the above statements, so here you can reform it to fit into the form of your new entity
// exp[0] here will be equivilant to g in your query
})
.OrderBy( ee => ee.COGCounter1 ) //order by any of the properties of RFConsumption
.ToList<RFConsumption>();
you should first add the entity RFConsumption:
public calss RFConsumption
{
public int COGCounter1 { get; set; }
public int BFCounter { get; set; }
....
}

LINQ to Entities combine two IQueryable<AnonymousType>

I have 2 queries which work fine:
var q = (from c in _context.Wxlogs
where (SqlFunctions.DatePart("Month", c.LogDate2) == m3) && (SqlFunctions.DatePart("Year", c.LogDate2) == y1)
group c by c.LogDate2
into g
orderby g.Key
let maxTemp = g.Max(c => c.Temp)
let minTemp = g.Min(c => c.Temp)
let maxHum = g.Max(c => c.Humidity)
let minHum = g.Min(c => c.Humidity)
select new
{
LogDate = g.Key,
MaxTemp = maxTemp,
MaxTempTime = g.FirstOrDefault(c => c.Temp == maxTemp).LogTime,
MinTemp = minTemp,
MinTempTime = g.FirstOrDefault(c => c.Temp == minTemp).LogTime,
MaxHum = maxHum,
MaxHumTime = g.FirstOrDefault(c => c.Humidity == maxHum).LogTime,
MinHum = minHum,
MinHumTime = g.FirstOrDefault(c => c.Humidity == minHum).LogTime,
});
var r = (from c in _context.Wxlogs
where
(SqlFunctions.DatePart("Month", c.LogDate2) == m3) &&
(SqlFunctions.DatePart("Year", c.LogDate2) == y1)
group c by c.LogDate2
into g
orderby g.Key
let maxDew = g.Max(c => c.Dew_Point)
let minDew = g.Min(c => c.Dew_Point)
//let maxWind = g.Max(c=> c.Wind_Gust)
let maxRainRate = g.Max(c => c.Rain_rate_now)
let maxPres = g.Max(c => c.Barometer)
let minPres = g.Min(c => c.Barometer)
select new
{
LogDate = g.Key,
MaxRainRateTime = g.FirstOrDefault(c => c.Rain_rate_now == maxRainRate).LogTime,
MaxPres = maxPres,
MaxPresTime = g.FirstOrDefault(c => c.Barometer == maxPres).LogTime,
MinPres = minPres,
MinPresTime = g.FirstOrDefault(c => c.Barometer == minPres).LogTime,
MinDew = minDew,
MinDewTime = g.FirstOrDefault(c => c.Dew_Point == minDew).LogTime,
MaxDew = maxDew,
MaxDewTime = g.FirstOrDefault(c => c.Dew_Point == maxDew).LogTime,
MaxRainRate = maxRainRate,
});
however when I try to combine them using union, in order to output the results to a WPF datgrid:
var result = r.Union(q);
the following error is thrown on the union:
Error 1 Instance argument: cannot convert from 'System.Linq.IQueryable<AnonymousType#1>' to 'System.Linq.ParallelQuery<AnonymousType#2>'
I can't seem to find a way to make this work and any help would be appreciated.
A "union" operation combines two sequences of the same type into a single set (i.e. eliminating all the duplicates). Since you clearly have sequences of two different types, you don't want a union operation. It looks like you want a "concat" operation, which just chains two sequences together. You need something like:
var result = r.Concat<object>(q);
However, since you're using L2E, your query will try to get executed on the server. Since your server won't allow you to combine your two queries (due to mismatched types), you need to execute them separately and then concat the sequences on the client:
var result = r.AsEnumerable().Concat<object>(q.AsEnumerable());
The use of AsEnumerable() runs the queries on the server and brings the results to the client.
Since it turns out that you want to combine the sequences next to each other (i.e. using the same rows in your grid but another group of columns), you actually want a join operation:
var result = from rrow in r.AsEnumerable()
join qrow in q.AsEnumerable() on rrow.LogDate equals qrow.LogDate
select new { rrow.LogDate,
rrow.MaxTemp, rrow.MaxTempTime,
rrow.MinTemp, rrow.MinTempTime,
rrow.MaxHum, rrow.MaxHumTime,
rrow.MinHum, rrow.MinHumTime,
qrow.MaxRainRate, qrow.MaxRainRateTime,
qrow.MaxPres, qrow.MaxPresTime,
qrow.MinPres, qrow.MinPresTime,
qrow.MaxDew, qrow.MaxDewTime,
qrow.MinDew, qrow.MinDewTime };

Resources