I have xml that looks like this:
<Doc>
<Thing>
<ID type="One">Fred</ID>
</Thing>
<Thing>
<ID>Bill</ID>
</Thing>
<Thing>
<ID type="Two">John</ID>
</Thing>
</Doc>
I can write LINQ to find the type="One" nodes. (or type="Two")
Dim ThingList As IEnumerable(Of XElement) = _
From el In doc...<Thing>.<ID> _
Where el.Attribute("type").Value = "One" _
Select el
How would I write a linq query to find the ID node that doesn't have a type attribute at all?
You should use the fact that Attribute() will return null/nothing if there's no such attribute.
In C# I would use:
var idsMissingType = doc.Descendants("ID") // Or whatever
.Where(x => x.Attribute("type") == null);
My guess is that the VB you want is:
Dim ThingList As IEnumerable(Of XElement) = _
From el In doc...<Thing>.<ID> _
Where el.Attribute("type") Is Nothing _
Select el
Related
I'm trying to make an extension method that takes in an expression that points to a property on an entity, and a constant string to compare it to using String.Contains, that first checks whether the string is null or empty, and applies the filter only if the string has a value. This is my first dabble in Expression Trees though, so I'm not really sure what's going on, and I now have an exception which I'm not sure how to cure...
I'm at this so far:
<System.Runtime.CompilerServices.Extension()>
Public Function CheckAndFilter(Of T)(source As System.Linq.IQueryable(Of T), expressionField As System.Linq.Expressions.Expression(Of System.Func(Of T, String)), compareTo As String) As IQueryable(Of T)
If String.IsNullOrEmpty(compareTo) Then
Return source
Else
Dim memberExp As Expressions.MemberExpression = DirectCast(expressionField.Body, Expressions.MemberExpression)
Dim param = Expressions.Expression.Parameter(GetType(T))
Dim method As Reflection.MethodInfo = GetType(String).GetMethod("Contains")
Dim compareToExpression = Expressions.Expression.Constant(compareTo)
Dim finalExpr = Expressions.Expression.Call(memberExp, method, compareToExpression)
Dim lambda = Expressions.Expression.Lambda(Of Func(Of T, Boolean))(finalExpr, param)
Return source.Where(lambda)
End If
End Function
I'm calling it like this, against a DbContext where I have a Customer entity with a FirstName string property:
Dim results = repository.Customers.CheckAndFilter(Function(c) c.FirstName, searchText)
And the exception is:
{"The parameter 'c' was not bound in the specified LINQ to Entities query expression."}
Any thoughts?
A ha!
It's because I've declared a new parameter rather than re-using the one passed in via the expression...
<System.Runtime.CompilerServices.Extension()>
Public Function CheckAndFilter(Of T)(source As System.Linq.IQueryable(Of T), expressionField As System.Linq.Expressions.Expression(Of System.Func(Of T, String)), compareTo As String) As IQueryable(Of T)
If String.IsNullOrEmpty(compareTo) Then
Return source
Else
Dim memberExp As Expressions.MemberExpression = DirectCast(expressionField.Body, Expressions.MemberExpression)
Dim method As Reflection.MethodInfo = GetType(String).GetMethod("Contains")
Dim compareToExpression = Expressions.Expression.Constant(compareTo)
Dim finalExpr = Expressions.Expression.Call(memberExp, method, compareToExpression)
Dim lambda = Expressions.Expression.Lambda(Of Func(Of T, Boolean))(finalExpr, expressionField.Parameters)
Return source.Where(lambda)
End If
End Function
I am pulling my Data using SQL to LINQ with XML Output and everything is working properly, except I am trying to add a counter under the select statement. Under New XElement("Message", "i") I need the i replaced with a 1, 2, 3... to reflect the number count of each data loop. My current output returns i for messageID and code is below using VB. I have struggled to find a solution any help would be appreciated.
i 'Need i as 1
Update
000076
0
i 'Need i as 2
Update
000104
0
Public Sub QOHPush()
Dim db As MYDataContext = New MYDataContext()
Dim QOH1 = <MyEnvelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="amzn-envelope.xsd">
<Header>
<DocumentVersion>1.01</DocumentVersion>
<MerchantIdentifier>Test</MerchantIdentifier>
</Header>
<MessageType>Inventory</MessageType>, _
<%= From c In db.Inventories _
Select New XElement("Message", _
New XElement("MessageID", "i"), _
New XElement("OperationType", "Update"), _
<Inventory>
<SKU><%= c.LocalSKU %></SKU>
<Quantity><%= c.QOH %></Quantity>
</Inventory>) %>
</MyEnvelope>
QOH1.Save("\\10.x.x.x\Backup\Products20110328134844.xml")
Have you considered this?
Dim QOH1 = <MyEnvelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="amzn-envelope.xsd">
<Header>
<DocumentVersion>1.01</DocumentVersion>
<MerchantIdentifier>Test</MerchantIdentifier>
</Header>
<MessageType>Inventory</MessageType>, _
<%= Dim counter as Integer = 0
From c In db.Inventories _
Select New XElement("Message", _
New XElement("MessageID", "i += 1"), _
New XElement("OperationType", "Update"), _
<Inventory>
<SKU><%= c.LocalSKU %></SKU>
<Quantity><%= c.QOH %></Quantity>
</Inventory>) %>
</MyEnvelope>
QOH1.Save("\\10.x.x.x\Backup\Products20110328134844.xml")
I've created a variable of a class type (CustomerInfo) to store a linq query result and get the error message 'nullable object must have a value' when I view or use the colResults variable, (SurveyDate is a nullable field in the sql table):
Dim var = SurveyDBcontext.QT_Survey_GetSurveySchedule(1, 1, 1).ToList()
Dim colResults = From query In var _
... _
Select New CustomerInfo With { _
.Address = comp.Address, _
.SurveyDate= query.SurveyDate}
If I change the above to:
Dim colResults = From query In var _
... _
Select New With { _
.Address = comp.Address, _
.SurveyDate= query.SurveyDate}
if works fine. Any ideas?
thanks.
Your 'Address' or 'ServeyDate' fields are returning null values and your CustomerInfo class does not allow null values.
The second example is generating an anonymous type which allows nulls. Can you check the actual type that is generated? Guessing SurveyDate is a nullable DateTime in the second example.
I've got a query in C# that is working for me to query the metadata for the Entity Framework. I need to convert it to VB.NET, but I'm struggling to convert the AS keyword to "cast" meta to System.Data.Metadata.Edm.EntityType. I've tried TryCast, CType, Cast, etc.
Here's the query in C#:
var queryResult = from meta in oc.MetadataWorkspace.GetItems(System.Data.Metadata.Edm.DataSpace.CSpace)
.Where(m => m.BuiltInTypeKind == System.Data.Metadata.Edm.BuiltInTypeKind.EntityType)
from p in (meta as System.Data.Metadata.Edm.EntityType).Properties
.Where(p => p.DeclaringType.Name == entityClassType.Name
&& p.Name == propertyName)
select p;
This is the closest I've come to getting it to compile in VB.NET (the As keyword in underlined and says ')' expected:
Dim query2 = _
From meta In entityObjectContext.MetadataWorkspace.GetItems(System.Data.Metadata.Edm.DataSpace.CSpace) _
.Where(Function(m) m.BuiltInTypeKind = System.Data.Metadata.Edm.BuiltInTypeKind.EntityType) _
From p In (meta As System.Data.Metadata.Edm.EntityType).Properties _
.Where(Function(p) p.DeclaringType.Name = entity.GetType().Name _
And p.Name = propertyName) _
Select p
This is killing me. I'm so close...
You can use CType to type cast:
...
From p In CType(meta, System.Data.Metadata.Edm.EntityType).Properties _
...
Update: Looking again at the query, I would suggest using OfType() instead:
From meta In entityObjectContext.MetadataWorkspace.GetItems(System.Data.Metadata.Edm.DataSpace.CSpace) _
.OfType(Of System.Data.Metadata.Edm.EntityType)() _
From p In meta.Properties _
Where p.DeclaringType.Name = entity.GetType().Name _
And p.Name = propertyName _
Select p
Update 2: Also, it looks like GetItems() has a generic version that I suspect will return only items of your desired type:
From meta In entityObjectContext.MetadataWorkspace.GetItems(Of System.Data.Metadata.Edm.EntityType)(System.Data.Metadata.Edm.DataSpace.CSpace) _
From p In meta.Properties _
Where p.DeclaringType.Name = entity.GetType().Name _
And p.Name = propertyName _
Select p
If I were writing this query in VB.NET, I would do it like this without the lambdas. I think it's easier to read, but they way you're doing it would probably be easier for a C# developer to read.
Dim query2 = _
From meta In entityObjectContext.MetadataWorkspace.GetItems(System.Data.Metadata.Edm.DataSpace.CSpace) _
Where m.BuiltInTypeKind = System.Data.Metadata.Edm.BuiltInTypeKind.EntityType _
From p In CType(meta, System.Data.Metadata.Edm.EntityType).Properties _
Where p.DeclaringType.Name = entity.GetType().Name _
And p.Name = propertyName) _
Select p
I am using Rob's implementation of LazyList and it is working great.
However, I am not able to get a .where clause working on a child entity of the type LazyList.
For eg. something like
var qry = orderRepository.GetOrders();
qry = from p in qry where p.Items.Where(t => t.Name == "test") select p;
produces the following compile time error:
Cannot implicitly convert type 'System.Collections.Generic.IEnumerable<Items>' to 'bool'
What is the correct way to query a child entity?
You need Any.
var qry = orderRepository.GetOrders();
qry = from p in qry where p.Items.Any(t => t.Name == "test") select p;
You already have a where clause, and using a second one won't do any good. The first where (the lowercase one) wants a boolean to be able to perform the filtering, but you are providing an IEnumerable<Items> (because that is what the second .Where returns). Any works the same as Where but returns a boolean whenever there's at least one item that matches the query you specified.
Not sure what you are trying to achieve with this statement.
If you want all the orders that have an item with the name "test" then use:
var qry = orderRepository.GetOrders();
qry = from p in qry where p.Items.Any(t => t.Name == "test") select p;
If you want all items that are named "test" then use:
var qry = orderRepository.GetOrders();
qry = from p in qry select p.Items.Where(t => t.Name == "test");