Match nHibernate expressions to nested tables? - nhibernate

Stupid nHibernate noob question, but I can't find the answer anywhere ...
I have a "product" class successfully mapped to a product table, and an "sku" class. Sku is a child object of "product" and the two tables in the DB are related by primary key.
So far all the basic nHibernate stuff works - I can run CRUD opeations against the databasse successfully. I can make expression based queries successfully, as in ...
Dim results As ArrayList = session.CreateCriteria(Of DataTransferObjects.Product) _
.Add(Expression.Like("Name", nameSearchString)) _
.List()
.. And the result is a list of product objects which successfully expose the expected Sku child objects. However, if I try the above code searching on field names from the Sku table, NHibernate throws an error:
Dim results As ArrayList = session.CreateCriteria(Of DataTransferObjects.Product) _
.Add(Expression.Like("SkuCode", skuSearchString)) _
.List()
Results in "could not resolve property: SkuCode of: Product"
This works:
Dim results As ArrayList = session.CreateCriteria(Of DataTransferObjects.Sku _
.Add(Expression.Like("SkuCode", skuSearchString)) _
.List()
But, unsurprisingly, it only returns Sku objects whereas I need the product object.
This also compiles:
Dim results As ArrayList = session.CreateCriteria(Of DataTransferObjects.Product) _
.Add(Expression.Like("Name", nameSearchString)) _
.CreateCriteria("Skus").Add(Expression.Like("SkuCode", skuSearchStrung)) _
.List()
But it returns nothing at all, even though the first expression is valid
How can I run an Expression.Like against fields in the Sku table?

I've solved this - thought I'd leave it here for anyone else to discover. This sort of thing seems very poorly documented:
Dim results As ArrayList = session.CreateCriteria(Of DataTransferObjects.Product) _
.CreateAlias("Skus", "sku") _
.Add(Expression.Or( _
Expression.Like("Name", nameSearchString), _
Expression.Like("sku.SkuCode", skuSearchStrung))) _
.List()
I've blogged about my frustrations with this framework:
http://mattthr.blogspot.com/2010/02/quey-across-join-in-nhibernate.html

Related

Min Max in LInq with VB.NET

I am needing help to using LINQ expressions under VB.NET.
I have a Class with 3 fields, I want to find the MIN and MAX of the COMBINED 3 fields (think SQL UNION). I have been able to cobble-up a LINQ expression that puts all 3 (decimal) fields into 1 (decimal) field... and it "should" be as easy as specifying the .Min or .Max property at the end of the expression... however, it keeps throwing an error for me... so, looking for some help.
Here is the LINQ expressions in VB.NET that returns a LIST of the UNION'd columns/fields...
Dim result As List(Of RValue) = MeterRoughnessMaster_R1.[Select](Function(x) New RValue() With { _
.RValue = x.RValueBOTH _
}).Union(MeterRoughnessMaster_R1.[Select](Function(x) New RValue() With { _
.RValue = x.RValueUP _
}).Union(MeterRoughnessMaster_R1.[Select](Function(x) New RValue() With { _
.RValue = x.RValueDN _
}))).ToList
The above needs to be re-worked so that "result" should hold a decimal value or MIN or MAX.
I tried this...
Dim result = MeterRoughnessMaster_R1.[Select](Function(x) New With { _
.RValue = x.RValueBOTH _
}).Union(MeterRoughnessMaster_R1.[Select](Function(x) New With { _
.RValue = x.RValueUP _
}).Union(MeterRoughnessMaster_R1.[Select](Function(x) New With { _
.RValue = x.RValueDN _
}))).Min
But it error'd with "At least one object must implement IComparable." so, I am missing a keyword someplace that would otherwise invoke IComparable (which is what I thought .Min would do)
I want above LINQ expression re-worked to simply return .Min (or .Max) to the variable "result" (decimal). The "RValue" Class can be abandoned if necessary... but the 3 fields from "MeterRoughnessMaster_R1" must remain. I want to do this in LINQ (VB.NET).
There's no need for that elaborate Union. You should be using SelectMany.
Dim allValues = MeterRoughnessMaster_R1.SelectMany(Function(x) {x.RValueBOTH, x.RValueUP, x.RValueDN}).ToArray()
Dim min = allValues.Min()
Dim max = allValues.Max()
Obviously you don't have to use the allValues variable and can get the min or max in one statement but you should use a variable if you want both.
EDIT: I should also note that if you do use a single statement to get just the min or just the max then you can drop the ToArray call too.
Dim min = MeterRoughnessMaster_R1.SelectMany(Function(x) {x.RValueBOTH, x.RValueUP, x.RValueDN}).Min()
Dim max = MeterRoughnessMaster_R1.SelectMany(Function(x) {x.RValueBOTH, x.RValueUP, x.RValueDN}).Max()

LinqPad Error: Lambda expression cannot be converted to 'String' because 'String' is not a delegate type

When using linqPad I get the following error:
Lambda expression cannot be converted to 'String' because 'String' is not a delegate type.
When copying in the following code.
Any idea what could be wrong. I am using the Entity Framework and have linqPad configured to read off an Entity Framework object.
Can I use linqPad to create EF queries or is it strictly linq?
dim db As PlanITEntities = New PlanITEntities
Dim projects = From p In db.Projects.Include(Function(p) p.AvailableSpaceTypes) _
.Include(Function(p) p.DisadvantageDegree) _
.Include(Function(p) p.FundingSources) _
.Include(Function(p) p.PartnerApprovalStatusCode) _
.Include(Function(p) p.PhysicalConstraintTypes) _
.Include(Function(p) p.PolicyConstraintTypes) _
.Include(Function(p) p.Profile) _
.Include(Function(p) p.Program) _
.Include(Function(p) p.Program1) _
.Include(Function(p) p.Recommendation) _
.Include(Function(p) p.RequestType) _
.Include(Function(p) p.SchematicDesignSource) _
.Include(Function(p) p.Recommendation1) _
.Include(Function(p) p.StatusCode) _
Where (p.DeleteFlag <> True) _
Select p
The problem appears to be that one or more of the properties of object "p" is not a string. However, you most likely are misunderstanding what .Include does. It eager-loads whichever related tables you specify. So if you had:
Dim projects = From p In db.Projects.Include("Managers")
it would eager-load all of the related records from your "Managers" table for each row in your "Projects" table when the query is executed. Somehow, I don't think this is what you are trying to accomplish with the code you posted.
the signature for include that takes a lambda expression is in the system.data.entity assembly, so probably won't work with linqPad.

Entity Framework 5 is sending back the wrong data

I have a very serious issue with EF sending back the wrong data. I know its wrong because I can run the same query against the same table in management studio and get a completely different result.
I did research the problem and found that some people were able resolve the issue by adding:
*DbContextSummary.Refresh(RefreshMode.StoreWins, result);*
When I try adding that I get this error:
The element at index 0 in the collection of objects to refresh has a null EntityKey property value or is not attached to this ObjectStateManager.
After I got that error I tried to do: DbContextSummary.Attach(result) and I received another error.
What is the proper solution and why does this happen?
Relevant Code (without the refresh call):
Private _dbContextSummary As BudgetEntities
Public ReadOnly Property DbContextSummary() As BudgetEntities
Get
If _dbContextSummary Is Nothing Then
_dbContextSummary = New BudgetEntities
End If
Return _dbContextSummary
End Get
End Property
<WebMethod()> _
Public Function GetSummaryData(ByVal month As String, ByVal year As String, ByVal expenseLine As String, ByVal organization As String) As List(Of SummaryModel)
Dim result As List(Of SummaryModel) = Nothing
result = (From s In DbContextSummary.FPRs _
Where s.FY = year _
Where s.Month = month _
Where s.FPRLine = expenseLine _
Where s.VP = organization
Group s By s.MgrID, s.ProgAdm, s.FinanceNumber, s.FinanceNumberName Into g = Group _
Order By g.FirstOrDefault.MgrLastName, g.FirstOrDefault.ProgAdm Ascending
Select New SummaryModel With { _
.Actual = g.Sum(Function(a) a.Actual), _
.Plan = g.Sum(Function(p) p.Plan), _
.YTDActual = g.Sum(Function(ya) ya.YTDActual), _
.YTDPlan = g.Sum(Function(yp) yp.YTDPlan), _
.FinanceNumber = g.FirstOrDefault.FinanceNumber, _
.FinanceNumberName = g.FirstOrDefault.FinanceNumberName, _
.MgrLastName = g.FirstOrDefault.MgrLastName + ", " + g.FirstOrDefault.MgrFirstName, _
.PlanYearTotal = g.FirstOrDefault.PlanYearTotal, _
.ProgAdm = g.FirstOrDefault.ProgAdm _
}).ToList()
Return result
End Function
What is the proper solution and why does this happen?
Simply put, there is no proper solution in your scenario. Refresh is not applicable at all after you have performed a projection (select new) into a type (SummaryModel) that isn't an entity. Your result collection does not contain entities but SummaryModels. You neither can apply Refresh nor Attach to this collection or its elements. Both methods are intended to work with model entities: Refresh updates properties of an already attached entity from the data store and Attach adds an entity to the context in state Unchanged.
I suggest that you open a new question and describe why you think that "EF is sending back the wrong data" and try to solve this problem. It's unlikely that re-loading provides correct data when loading delivers a wrong result.

Group and sum list (vb.net)

I've got a list of objects
Class Bundledtellingen
Property tTimestamp As String
Property tValue As Double
End Class
Now I am trying to group this list by tTimestamp and sum tValue. By searching similar questions it was clear the best way to go is using Linq. I've put this together:
Dim query = bundledlist.GroupBy( _
Function(telling) telling.tTimestamp, _
Function(telling) telling.tTimestamp, _
Function(ts, values) New With _
{.Key = ts, _
.Sum = values.Sum()} _
)
Using writer As StreamWriter = New StreamWriter("C:\test.txt")
For Each result In query
writer.WriteLine(result.Key & " " & result.Sum)
Next
End Using
As far as I can tell by looking at the examples at http://msdn.microsoft.com/en-us/library/bb534493.aspx#Y0 this should work, though i get the following exception: "Overload resolution failed because no accessible 'Sum' accepts this number of arguments."
You've specified one unnecessary parameter into your GroupBy call. Thy that one:
Dim query = bundledlist.GroupBy( _
Function(telling) telling.tTimestamp, _
Function(ts, values) New With _
{.Key = ts, _
.Sum = values.Sum()} _
)
The first one is key selector, the second is result selector.
Your call with 3 parameters has additional value selector, where you're selecting Function(telling) telling.tTimestamp twice - once for Key and once for Value. That's why your Sum didn't work: you tried call Sum on telling.tTimestamp.

Linq to object: ToList can not convert to generic list

Dim tenItem = From t In _InvalidFeeList _
From i In ItemCount _
Where t.FeeCode <> i.FeeCode _
Order By t.Description _
Ascending Take (10)
Dim feeList As List(Of AccessorialFee) = tenItem.ToList()
I am getting "Can not convert to System.generic.list" error. I look all over for this error and it seem like my code should work for example here
I don't get it. Can someone tell me where i got it wrong?
edit: I think i should explain what I'm trying to do here. I want to compare two object list and select the object from the InvalidFeeList if the FeeCode is not equal to the object in ItemCount FeeCode and take the first 10 objects from the InvalidFeeList.
The problem is that you've got two "From" clauses, so the result isn't just the type of the original collection. It's easy to fix though - just add a projection at the end:
Dim tenItem = From t In _InvalidFeeList _
From i In ItemCount _
Where t.FeeCode <> i.FeeCode _
Order By t.Description _
Ascending Take (10) _
Select t ' This is the new line '
Dim feeList As List(Of AccessorialFee) = tenItem.ToList()
EDIT: Are you trying to find items in _InvalidFeeList whose FeeCode isn't present in any item in ItemCount? If so, I suggest this change:
Dim feeCodes = From i In ItemCount Select i.FeeCode
Dim feeCodeSet = new HashSet(Of FeeCodeType)(feeCodes)
Dim tenItem = From t in _InvalidFeeList
Where Not feeCodeSet.Contains(t.FeeCode)
Order By t.Description _
Ascending Take (10)
Dim feeList As List(Of AccessorialFee) = tenItem.ToList()
As you can see, I didn't know the type of FeeCode, and VB is not exactly my strong point, but I hope you get the general idea. This suggestion is assuming you're using LINQ to Objects - if you're using LINQ to SQL I'm not sure of the best way to do it. Note that we no longer need the Select clause for tenItem as we're only dealing with a single collection now.
_InvalidFeeList is not of type List(Of AccessorialFee)
[Edit] Try this and add a breakpoint and a watch:
Dim tenItem = (From t In _InvalidFeeList _
From i In ItemCount _
Where t.FeeCode <> i.FeeCode _
Order By t.Description _
Ascending Take (10)).ToList().GetType()