Select the max,min of nested lists vb.net - vb.net

I have these objects
Public Class Class1
Public Property Type As String
Public Property SpecLimits As Limits
End Class
Public Class Limits
Public Property MinValue As Double?
Public Property MaxValue As Double?
End Class
I can have more Type-s with their Speclimits values. I need to find the maximum of MaxValue. I can make it with a for each to check every time which number is bigger, but I thought maybe their is some linq with what this could be achievable.
I found something like this in c#
var maxItem = emplist
.Select((emp, index) => new
{
maxProject = emp.project
.Select((proj, pIndex) => new{ proj, pIndex })
.OrderByDescending(x => x.proj.ID)
.First(),
emp, index
})
.OrderByDescending(x => x.maxProject.proj.ID)
.First();
but I can't translate it to vb.net
Any help is appreciated!

I guess you want something like this:
Dim minValue As Double = list.Min(Function(x) x.SpecLimits.MinValue)
Dim maxValue As Double = list.Max(Function(x) x.SpecLimits.MaxValue)

Related

group XDocument by multiple nodes (dynamic)

I have below data coming in as DataTable. If I directly convert it to XML I get nice xdocument object.
However problem is I need to group it by first 4 columns so that XML is shown as below. I know of only three nodes 'Segment', 'Price' and 'Qty' rest columns in datatable could be dynamic and cannot use hardcoded names (except for above 3)
<ROOT>
<ROW>
<Col1>CESLP</Col1>
<Col2>MRP</Col2>
<Col3>372</Col3>
<Date>20040101</Date>
<BID_INTERVALS>
<SEGMENT>1</SEGMENT>
<Price>10</Price>
<QTY>5</QTY>
</BID_INTERVALS>
<BID_INTERVALS>
<SEGMENT>2</SEGMENT>
<Price>15</Price>
<QTY>6</QTY>
</BID_INTERVALS>
</ROW>
<ROW>
<Col1>CESLP</Col1>
<Col2>MRP</Col2>
<Col3>372</Col3>
<Date>20040102</Date>
<BID_INTERVALS>
<SEGMENT>1</SEGMENT>
<Price>11</Price>
<QTY>5</QTY>
</BID_INTERVALS>
<BID_INTERVALS>
<SEGMENT>2</SEGMENT>
<Price>14.5</Price>
<QTY>6</QTY>
</BID_INTERVALS>
</ROW>
Any solution? I'm stuck for quite some time, tried xdocument group by 'except' but didn't worked for me.
Edit1:
I'm using below code to group the records (using solution from here
dataTable.AsEnumerable()
.GroupBy(r => new NTuple<object>(from column in colNames select r[column]))
.Select(g => g.CopyToDataTable()).ToList();
It's not entirely clear from the bitmap in your question whether you intially have a DataTable or an XDocument. So let's assume you have an XDocument, and you would like to group the child rows of the root element by the values of their first four columns, with the remaining values collected under a sequence of elements named <BID_INTERVALS>.
This can be accomplished using the following extension method:
public static partial class XNodeExtensions
{
public static XElement CopyAndGroupChildrenByColumns(this XElement root, Func<XName, int, bool> columnFilter, XName groupName) =>
new XElement(root.Name,
root.Attributes(),
root.Elements()
.Select((row) => (row, key : row.Elements().Where((e, i) => columnFilter(e.Name, i)).Select(e => (e.Name, e.Value)).ToHashSet()))
.GroupByKeyAndSet(pair => pair.row.Name, pair => pair.key)
.Select(g => new XElement(g.Key.Key,
g.Key.Set.Select(p => new XElement(p.Name, p.Value)).Concat(g.Select(i => new XElement(groupName, i.row.Elements().Where((e, i) => !columnFilter(e.Name, i))))))));
public static IEnumerable<IGrouping<(TKey Key, HashSet<TItem> Set), TSource>> GroupByKeyAndSet<TSource, TKey, TItem>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, HashSet<TItem>> setSelector) =>
Enumerable.GroupBy(source, (i) => (keySelector(i), setSelector(i)), new CombinedComparer<TKey, HashSet<TItem>>(null, HashSet<TItem>.CreateSetComparer()));
}
public class CombinedComparer<T1, T2> : IEqualityComparer<ValueTuple<T1, T2>>
{
readonly IEqualityComparer<T1> comparer1;
readonly IEqualityComparer<T2> comparer2;
public CombinedComparer(IEqualityComparer<T1> comparer1, IEqualityComparer<T2> comparer2) => (this.comparer1, this.comparer2) = (comparer1 ?? EqualityComparer<T1>.Default, comparer2 ?? EqualityComparer<T2>.Default);
public bool Equals(ValueTuple<T1, T2> x, ValueTuple<T1, T2> y) => comparer1.Equals(x.Item1, y.Item1) && comparer2.Equals(x.Item2, y.Item2);
public int GetHashCode(ValueTuple<T1, T2> obj) => HashCode.Combine(comparer1.GetHashCode(obj.Item1), comparer2.GetHashCode(obj.Item2));
}
Then, given some XDocument doc, you can do:
// Group by the first four columns with all remaining elements collected under a <BID_INTERVALS> sequence of elements:
XName groupName = doc.Root.Name.Namespace + "BID_INTERVALS";
var grouped = doc.Root.CopyAndGroupChildrenByColumns((n, i) => (i < 4), groupName);
var newDoc = new XDocument(grouped);
If, on the other hand, you have a DataTable dt not an XDocument, you can convert the table to an XDocument directly using the following extension method:
public static partial class XNodeExtensions
{
public static XDocument ToXDocument(this DataTable dt, XmlWriteMode mode = XmlWriteMode.IgnoreSchema)
{
var doc = new XDocument();
using (var writer = doc.CreateWriter())
dt.WriteXml(writer, mode);
return doc;
}
}
And then do:
var doc = dt.ToXDocument(XmlWriteMode.IgnoreSchema);
Demo fiddle here.

Ravendb LoadDocument showing NULL value

I have following two Collections in RavenDB.Please help me for creating index for getting data from both collection.
public class Ticket
{
public string TicketID{get;set;}
public double Total{get;set;}
}
public class ImportTiming
{
public string Id{get;set;}
public DateTime ExtractTime{get;set;}
}
AND
public class ResultClass
{
public string TicketID{get;set;}
public double Total{get;set;}
public DateTime ExtractTime{get;set;}
}
TicketID(Ticket) & Id(ImportTiming) are same.I am using LoadDocument for ExtractTime but it is showing NULL value.
Thanks in advance!!!
Finally i got solution...
Bellow is the Map-Reduce function,in which i have used LoadDocument<> for selecting data from ImportTiming Document.
public class IdxJoinBetweenCollections : AbstractIndexCreationTask<Ticket,JoinBetweenCollections.ResultClass>
{
public IdxJoinBetweenCollections()
{
Map = docs => from doc in docs
let TimeDoc = LoadDocument<ImportTiming>("ImportTiming/" + doc.TicketID)
select new
{
ID = doc.TicketID,
Total = doc.Total,
ExtractTime = TimeDoc.ExtractComplete,
};
Reduce = results => from res in results
group res by res.ID into g
select new
{
ID = g.Key,
Total = g.Select(x => x.Total).FirstOrDefault(),
ExtractTime = g.Select(x => x.ExtractTime).FirstOrDefault(),
};
}
}
In LoadDocument("ImportTiming/" + doc.TicketID),i have used CollectionName followed by Id so that i gets whole document.If i dont use CollectionName then it shows NULL value.
Reference:http://ravendb.net/docs/2.0/client-api/querying/static-indexes/indexing-related-documents

How to get nested objects using ICriteria Projections

I have data model like this:
class Hand {
public int id;
...
}
class Person {
public int id;
public string name;
public IList<Hand> hands;
...
}
To get data from database, I do this:
ICriteria criteria = databaseSession.CreateCriteria(typeof(Person));
ProjectionList projections = Projections.ProjectionList();
projections
.Add(Projections.Property("id").As("id"))
.Add(Projections.Property("name").As("name"))
.Add(Projections.Property("hands").As("hands"));
projections.Add(Projections.GroupProperty("id"));
projections.Add(Projections.Count("id"), "count");
criteria.SetProjection(projections);
criteria.SetResultTransformer(
NHibernate.Transform.Transformers.AliasToBean(typeof(PersonDTO)));
But NHibernate does not load nested objects in hands property. It just gives null.
Can anyone help me how to get nested objects filled as well (for more than one level depth). Using projections instead of query would be better for me.
Note: It would not be issue in the mapping, because when I loaded data without any projection, it worked well.
a possible solution
var query = databaseSession.CreateCriteria(typeof(Person))
.JoinAlias("hands", "hand")
.SetProjection(Projections.ProjectionList()
.Add(Projections.Property("Id"))
.Add(Projections.Property("Name"))
.Add(Projections.Property("hand.Id"))
.Add(Projections.Property("hand.Foo")))
.List<object[]>()
.GroupBy(arr => (int)arr[0])
.Select(g => new PersonDTO
{
Id = g.Key,
Name = g.First().Name,
Hands = g.Select(arr => new Hand { Id = arr[2], Foo = arr[3] }).ToList(),
});
var results = query.ToList();

Does Dynamic Linq support BindingList<T>?

Question
I'm trying to use the Dynamic Linq Sample from Microsoft with BindingList<T> objects. But it looks like the Dynamic Linq will only work with IQueryable. What's the deal here, why doesn't BindingList<T> implement IQueryable. And is there a way around this?
Background Detail: I have many data sets that I need to dynamically filter at run time. Here is an example:
BindingList<MyObject> list = new BindingList<MyObject>();
MyObject selectedObj = list.FirstOrDefault(o => o.Name == "Master P")
// then later ...
MyObject selectedObj = list.FirstOrDefault(o => o.City == "Boston")
I am trying to make these queries dynamic, so the user can choose from all properties of MyObject to use in the query.
There is an Extension method on BindingList; AsQueryable(). So you can use
list.AsQueryable();
But if you want to search on all criteria could you create a search that uses an instance of MyObject as the search criteria and then generated a result set based on the Criteria in the object using standard link.
For example:
public List<MyObject> Search(MyObject SearchCriteria)
{
BindingList<MyObject> list = new BindingList<MyObject>();
list.Add(new MyObject("Test", "Boston"));
list.Add(new MyObject("Test2", "Atlanta"));
IEnumerable<MyObject> results = list.AsEnumerable();
if (!String.IsNullOrEmpty(SearchCriteria.Name))
results = results.Where(l => l.Name.Contains(SearchCriteria.Name));
if (!String.IsNullOrEmpty(SearchCriteria.City))
results = results.Where(l => l.City.Contains(SearchCriteria.City));
return results.ToList();
}
So in the following, Results1 will have 2 results and Results 2 will have only 1.
List<MyObject> results1 = Search(new MyObject("Test", ""));
List<MyObject> results2 = Search(new MyObject("Test", "Boston"));
I used a simple structure for MyObject as an example in this:
public class MyObject
{
public MyObject(string name, string city)
{
this.Name = name;
this.City = city;
}
public string Name { get; set; }
public string City { get; set; }
}

Update SqlCE database Linq-to-Sql

When I update the database, I have to hard code mapping of each property, because using attach results in exception. This does not seem too elegant. Is there some easier solution here I'm not aware of? My code is below, showing the "MapData" method I call for this purpose:
Btw, entity classes (here; Users) are autogenerated with SqlMetal.
Public Class UserDataService
Public Sub Save(ByVal user As Users)
Dim ctx As New TestDB(connection)
Dim id As Integer = user.Id
If user.Id = 0 Then
Insert(user)
Else
Dim q = (From n In ctx.Users Where n.Id = id Select n).Single
q.MapData(user)
For Each o In user.Orders
o.Save()
Next
' ctx.Users.Attach(user, q) ' Does not work
' ctx.Users.Attach(user, True) ' Does not work
End If
ctx.SubmitChanges()
ctx.Dispose()
End Sub
End Class
Partial Public Class Users
Public Sub MapData(ByVal row As Users)
Me.Name = row.Name
End Sub
End Class
EDIT1:
Exceptions:
ctx.Users.Attach(user, q)
Cannot add an entity with a key that is already in use.
ctx.Users.Attach(user, True)
An entity can only be attached as modified without original state if it declares a version member or does not have an update check policy.
EDIT2:
I tried to add a column timestamp, which I believe is supposed to satisfy the last mentioned exception. So I add the column shown here. This doesn't help, but perhaps I need to make some further settings for that to be effective?
This way should work:
ctx.Users.Attach(user)
ctx.Refresh(RefreshMode.KeepCurrentValues, user) 'this line is important
ctx.SubmitChanges()
This is my console test app(it works), in C# though:
class Program
{
public static void Main(string[] args)
{
var t = new Test();
Customer c = t.GetCustomer();
c.CompanyName = "X";
t.AttachCustomer(c);
}
class Test
{
public Customer GetCustomer()
{
Customer cust;
using(DataContext db = new DataContext())
{
cust = db.Customers.Where(x => x.CustomerID == "ALFKI").Single();
db.Dispose();
}
return cust;
}
public void AttachCustomer(Customer cx)
{
using (DataContext db = new DataContext())
{
db.Customers.Attach(cx);
db.Refresh(RefreshMode.KeepCurrentValues, cx);
db.SubmitChanges();
db.Dispose();
}
}
}
}