Simplifying multiple for each loops in LINQ - vb.net

in my prev question i was suggested with LINQ solution. It was great and simple. I tried to solve next similar but a bit diff problem with similar approach but i failed.
how can i make the below code better
For Each Item As ListViewItem In RoomsListView.Items
For Each Item1 As Room In myBookedRooms
If Item1.UIN = Item.SubItems(1).Text Then
Item.Checked = True
End If
Next
Next

Sorry - can read but not write VB...
In C# Linq, your query would be something like:
var query = from room in RoomsListView.Items
from bookedRoom in myBookedRooms
where ((Room)bookedRoom).UIN == room.SubItems(1).Text
select room;
foreach (var room in query)
{
room.Checked = true;
}

You can use Join for that. Here is a C# sample:
var itemsToUpdate = RoomsListView.Items
.Cast<ListViewItem>()
.Join(myBookedRooms,
Item => Item.SubItems(1).Text,
Item1 => Item1.UIN,
(Item, Item1) => Item);
foreach (var item in itemsToUpdate)
item.Checked = true;

Related

Convert a Linq result to a datatable

I am trying to convert a Linq result in to a datatable
I have a linq that is created from a dataset of many tables. It returns results, but I need to get the results in to a new datatable.
Examples I have seen say I sould be able to use .CopyToDataTable But for some reason this doesn't work?
I have noticed that I can to .ToArray perhaps I can then turn the array in to a datatable? Seems line an unnecessary step?
Here is my query: (it works)
Dim R2 = From Inq In DS.Tables!CNLocalInquiry.AsEnumerable()
Join Cust In DS.Tables!CustomerID.AsEnumerable() On Inq.Field(Of Integer)("CNLocalInquiry_Id") Equals Cust.Field(Of Integer)("CNLocalInquiry_Id")
Select New With {.date = Inq.Field(Of String)("date"),
.CName = Cust.Field(Of String)("CustomerNumber"),
.Name = Cust.Field(Of String)("name")}
Dim MemberInq as new datatable
MemberInq = R2.CopyToDataTable() <-- this doesn't work
This is what my query returns:
(this is the easy to code way... this will not be performant for large datasets)
public static class ToolsEx
{
public static DataTable ToDataTable<T>(this IEnumerable<T> items)
{
var t = typeof(T);
var dt = new DataTable(t.Name);
var props = t.GetProperties()
.Select(p => new { N = p.Name, Getter = p.GetGetMethod() })
.Where(p => p.Getter != null)
.ToList();
props.ForEach(p => dt.Columns.Add(p.N));
foreach (var item in items)
dt.Rows.Add(props.Select(p => p.Getter.Invoke(item, null)).ToArray());
return dt;
}
}
I've saved this as an extension method and it's always worked perfectly:
https://msdn.microsoft.com/en-us/library/bb669096.aspx
Examples here:
https://msdn.microsoft.com/en-us/library/bb386921.aspx
Hope that does the trick!

NHibernate Linq Query with Projection and Count error

I have the following query:
var list = repositoy.Query<MyClass>.Select(domain => new MyDto()
{
Id = domain.Id,
StringComma = string.Join(",", domain.MyList.Select(y => y.Name))
});
That works great:
list.ToList();
But if I try to get the Count I got an exception:
list.Count();
Exception
NHibernate.Hql.Ast.ANTLR.QuerySyntaxException
A recognition error occurred. [.Count[MyDto](.Select[MyClass,MyDto](NHibernate.Linq.NhQueryable`1[MyClass], Quote((domain, ) => (new MyDto()domain.Iddomain.Name.Join(p1, .Select[MyListClass,System.String](domain.MyList, (y, ) => (y.Name), ), ))), ), )]
Any idea how to fix that without using ToList ?
The point is, that we should NOT call Count() over projection. So this will work
var query = repositoy.Query<MyClass>;
var list = query.Select(domain => new MyDto()
{
Id = domain.Id,
StringComma = string.Join(",", domain.MyList.Select(y => y.Name))
});
var count = query.Count();
When we use ICriteria query, the proper syntax would be
var criteria = ... // criteria, with WHERE, SELECT, ORDER BY...
// HERE cleaned up, just to contain WHERE clause
var totalCountCriteria = CriteriaTransformer.TransformToRowCount(criteria);
So, for Count - use the most simple query, i.e. containing the same JOINs and WHERE part
If you really don't need the results, but only the count, then you shouldn't even bother writing the .Select() clause. Radim's answer as posted is a good way to both get the results and the count, but if your database supports it, use future queries to execute both in the same roundtrip to the database:
var query = repository.Query<MyClass>;
var list = query.Select(domain => new MyDto()
{
Id = domain.Id,
StringComma = string.Join(",", domain.MyList.Select(y => y.Name))
}).ToFuture();
var countFuture = query.Count().ToFutureValue();
int actualCount = countFuture.Value; //queries are actually executed here
Note that there in NH prior to 3.3.3, this would still execute two round-trips (see https://nhibernate.jira.com/browse/NH-3184), but it would work, and if you ever upgrade NH, you get a (minor) performance boost.

DetachedCriteria equivalent needed

I need the DetachedCriteria equivalent to the following HQL:
select obj
from Objects obj, Text text
where obj.TextId = text.TextId and <Some_Other_Condition>
order by text.Value
Thanx
It's all depending of your Mapped objects
Here is an example:
var criteriaObject = DetachedCriteria.For(typeof(Objects))
.CreateAlias("TextReference", "text")
.Add(Restrictions.Eq("Activate", true))
.AddOrder(new Order("text.Value", true));
Hope it helps

LINQ & Lambda Expressions equivalent of SQL In

Is there a lambda equivalent of IN? I will like to select all the funds with ids either 4, 5 or 6. One way of writing it is:
List fundHistoricalPrices = lionContext.FundHistoricalPrices.Where(fhp => fhp.Fund.FundId == 5 || fhp.Fund.FundId == 6 || fhp.Fund.FundId == 7).ToList();
However, that quickly becomes unmanageable if I need it to match say 100 different fundIds. Can I do something like:
List
fundHistoricalPrices =
lionContext.FundHistoricalPrices.Where(fhp
=> fhp.Fund.FundId in(5,6,7)).ToList();
It's somewhere along these lines, but I can't quite agree with the approach you have taken. But this will do if you really want to do this:
.Where(fhp => new List<int>{5,6,7}.Contains( fhp.Fund.FundId )).ToList();
You may want to construct the List of ids before your LINQ query...
You can use the Contains() method on a collection to get the equivalent to in.
var fundIds = new [] { 5, 6, 7 };
var fundHistoricalPrices = lionContext.FundHistoricalPrices.Where(fhp => fundIds.Contains(fhp.Fund.FundId)).ToList();
You could write an extension method like this :
public static bool In<T>(this T source, params T[] list)
{
if(null==source) throw new ArgumentNullException("source");
return list.Contains(source);
}
Then :
List fundHistoricalPrices = lionContext.FundHistoricalPrices.Where(fhp => fhp.Fund.FundId.In(5,6,7)).ToList();
No, the only similar operator i'm aware of is the Contains() function.
ANother was is to construct your query dynamically by using the predicate builder out of the LINQkit: http://www.albahari.com/nutshell/predicatebuilder.aspx
Example
int[] fundIds = new int[] { 5,6,7};
var predicate = PredicateBuilder.False<FundHistoricalPrice>();
foreach (int id in fundIds)
{
int tmp = id;
predicate = predicate.Or (fhp => fhp.Fund.FundId == tmp);
}
var query = lionContext.FundHistoricalPrices.Where (predicate);

TableName in Linq

My Sql Query in Vb.net is like this:
Dim TableName As String ="City"
Dim Str As String="Select * from "+TableName+""
I got TableName from another Form .how we can do this in linq?
can we use TableName in Linq query dynamically?
please help me?
Sorry for my example being in C#, but my Vb is rusty. I can read it, but not write it very well off the top of my head.
The best way I can think to do this is to use reflection and extension methods rather than LINQ syntax.
PropertyInfo info = dataContext.GetType().GetProperty( "City" );
IQueryable table = info.GetValue( dataContext, null ) as IQueryable;
var query = table.Where( t => t.Column == "Value" )
.Select( t => t.OtherColumn );
I'm assuming LINQtoSQL in this example and so am getting the object from the datacontext. If you're using something else, you'll need to adjust the method of finding the object.
You could also use a stack of if-then statements based on the value of the table name. If the number of possible tables was fixed and small, this might be better.
i got the idea, thanks, very helpful, however i couldnt be able to see those properties.
string linqObjectName = "Test";
PropertyInfo info = db.GetType().GetProperty(linqObjectName);
IQueryable table = info.GetValue(db, null) as IQueryable;
PropertyInfo[] properties = table.GetType().GetProperties();
ltr.Text += "properties: <hr size=1/>";
foreach (PropertyInfo p in properties)
{
ltr.Text += p.Name + "<br />";
}
and thats the result;
properties:
Context
IsReadOnly
Edit: I found it!
PropertyInfo[] properties =
table.Where("WebRef = \"" + webref + "\"").ElementType.GetProperties();