Entity Framework 0 to 1 relationship - Object Reference Not Set - vb.net

Having a bit of trouble having not long started with Entity Framework.
I have two tables which have a 0 to 1 relationship. When I select a row from the main table (staff) it's fine unless I select a row that has no joining record in the second table (status). If I do this, then it throws up 'Object reference not set to instance of an object' when it's trying to access the proprty of the second table:
If Not cls.STATUS_DESC.STAFF_INFO Is DBNull.Value Then
lblStatusDescription.Text = cls.STATUS_DESC.STAFF_INFO
End If
The LINQ I use to get the record is:
Dim account As STAFF =
(From a In sa.STAFFs
Where a.STAFF_NO = staffno
Select a).FirstOrDefault
There is no direct reference to the sub table in the statement, however the join is defined in the database diagram which allows me to reference the properties.
I'm certain it's a very basic issue, but like I said I've only just started using it!

I'm not sure if I can interpret your code correctly but I think it has to do with the Lazy Loading feature of Entity Framework. You must explicitly include the reference to load it into memory. You can to this by using the Include() method as below. I assume that STATUS_DESC is the name of the navigation property. Replace it with the actual one if I'm wrong:
Dim account As STAFF =
(From a In sa.STAFFs Where a.STAFF_NO = staffno Select a) _
.Include("STATUS_DESC") _
.FirstOrDefault

Got around it by adding:
If Not cls.STATUS_DESC Is Nothing Then
end if
to the property call, which seems fairly obvious now I think about it. Is this the most efficient way though, I would have thought that EF would have been able to handle a simple left join.

Related

LINQ retrieving a record based on date

I am trying to learn a bit about ling. in the code below, I'm trying to retrieve records that have an activeuntil date which after the current date.
Dim context As DynamicsCRMEntities = New DynamicsCRMEntities()
Dim CustomerNoticeQuery = From NewsArticles In context.BusinessUnitNewsArticles Where NewsArticles.NewsArticle Like "customer" Select NewsArticles.ArticleTitle, NewsArticles.NewsArticle, NewsArticles.ActiveUntil
For Each result In CustomerNoticeQuery
If Date.Now.Date >= result.ActiveUntil Then
CustomerNotice.Text = result.NewsArticle.ToString
End If
Next
I keep running into this error but cannot get my head around it
System.NotSupportedException: 'LINQ to Entities does not recognize the method 'Boolean LikeString(System.String, System.String, Microsoft.VisualBasic.CompareMethod)' method, and this method cannot be translated into a store expression.'
The Like operator you are using there is VB-specific and, as the error message says, is not supported by EF. You need to use standard .NET functionality that the LINQ to Entities provider understands. If you want to do a partial match on Strings, that means using String.Contains:
Dim CustomerNoticeQuery = From NewsArticles In context.BusinessUnitNewsArticles
Where NewsArticles.NewsArticle.Contains("customer")
Select NewsArticles.ArticleTitle, NewsArticles.NewsArticle, NewsArticles.ActiveUntil
You really ought to break your LINQ queries over multiple lines like that too, for the sake of readability.
Note that that addresses your actual issue, which has nothing to do with dates, so the date part to the question was completely irrelevant. That said, why would you do a query with a Where clause and then use a loop to filter the results of that query? Why would you not include the additional filter in the Where clause? I'd also consider using a better subject variable name in the query:
Dim today = Date.Today
Dim CustomerNoticeQuery = From article In context.BusinessUnitNewsArticles
Where article.NewsArticle.Contains("customer")
And article.ActiveUntil < today
Select article.ArticleTitle, article.NewsArticle, article.ActiveUntil

How to use LINQ to Entities to make a left join using a static value

I've got a few tables, Deployment, Deployment_Report and Workflow. In the event that the deployment is being reviewed they join together so you can see all details in the report. If a revision is going out, the new workflow doesn't exist yet new workflow is going into place so I'd like the values to return null as the revision doesn't exist yet.
Complications aside, this is a sample of the SQL that I'd like to have run:
DECLARE #WorkflowID int
SET #WorkflowID = 399 -- Set to -1 if new
SELECT *
FROM Deployment d
LEFT JOIN Deployment_Report r
ON d.FSJ_Deployment_ID = r.FSJ_Deployment_ID
AND r.Workflow_ID = #WorkflowID
WHERE d.FSJ_Deployment_ID = 339
The above in SQL works great and returns the full record if viewing an active workflow, or the left side of the record with empty fields for revision details which haven't been supplied in the event that a new report is being generated.
Using various samples around S.O. I've produced some Entity to SQL based on a few multiple on statements but I feel like I'm missing something fundamental to make this work:
int Workflow_ID = 399 // or -1 if new, just like the above example
from d in context.Deployments
join r in context.Deployment_Reports.DefaultIfEmpty()
on
new { d.Deployment_ID, Workflow_ID }
equals
new { r.Deployment_ID, r.Workflow_ID }
where d.FSJ_Deployment_ID == fsj_deployment_id
select new
{
...
}
Is the SQL query above possible to create using LINQ to Entities without employing Entity SQL? This is the first time I've needed to create such a join since it's very confusing to look at but in the report it's the only way to do it right since it should only return one record at all times.
The workflow ID is a value passed in to the call to retrieve the data source so in the outgoing query it would be considered a static value (for lack of better terminology on my part)
First of all don't kill yourself on learning the intricacies of EF as there are a LOT of things to learn about it. Unfortunately our deadlines don't like the learning curve!
Here's examples to learn over time:
http://msdn.microsoft.com/en-us/library/bb397895.aspx
In the mean time I've found this very nice workaround using EF for this kind of thing:
var query = "SELECT * Deployment d JOIN Deployment_Report r d.FSJ_Deployment_ID = r.Workflow_ID = #WorkflowID d.FSJ_Deployment_ID = 339"
var parm = new SqlParameter(parameterName="WorkFlowID" value = myvalue);
using (var db = new MyEntities()){
db.Database.SqlQuery<MyReturnType>(query, parm.ToArray());
}
All you have to do is create a model for what you want SQL to return and it will fill in all the values you want. The values you are after are all the fields that are returned by the "Select *"...
There's even a really cool way to get EF to help you. First find the table with the most fields, and get EF to generated the model for you. Then you can write another class that inherits from that class adding in the other fields you want. SQL is able to find all fields added regardless of class hierarchy. It makes your job simple.
Warning, make sure your filed names in the class are exactly the same (case sensitive) as those in the database. The goal is to make a super class model that contains all the fields of all the join activity. SQL just knows how to put them into that resultant class giving you strong typing ability and even more important use-ability with LINQ
You can even use dataannotations in the Super Class Model for displaying other names you prefer to the User, this is a super nice way to keep the table field names but show the user something more user friendly.

R programming: Creating a table in db through R

I have a matrix called "final_set" which gets created in my R code. Using some of the columns from this final set, I want to create a database table. I'm using the RJDBC package to make this happen.
However, for some reason its not recognizing "final_set" . I know my connection is okay because I've tried out other sql queries using that.
Could anyone help me with this please?
SqlStr = paste("SELECT",
S_Vars, ",", #Global Variable
final_set$pub_idx, ",",
final_set$qty_idx
into dbo.temp1
"from",
final_set,
sep = ""
)
dbSendUpdate(conn,SqlStr)
Error: Error in paste(**): object final_set not found
I think you want your query to be:
SqlStr = paste("SELECT",
S_Vars, #Global Variable
", pub_idx, qty_idx into dbo.temp1 from final_set")
R objects that are not strings shouldn't go in your query as R objects, as their values (not their names) will be coerced to strings.
I'm still a little confused as to your goal. If you're trying to create a table out of an R object, (i.e., final_set is not already a table in your database), then the database won't be able to select columns from final_set. Rather, you should use a function like dbWriteTable. If I'm correct about that, then I think what you're looking for is
dbWriteTable(conn, "temp1", final_set[, c(S_Vars, "pub_idx", "qty_idx")]

How do I use Linq-to-sql to iterate db records?

I asked on SO a few days ago what was the simplest quickest way to build a wrapper around a recently completed database. I took the advice and used sqlmetal to build linq classes around my database design.
Now I am having two problems. One, I don't know LINQ. And, two, I have been shocked to realize how hard it is to learn. I have a book on LINQ (Linq In Action by Manning) and it has helped some but at the end of the day it is going to take me a couple of weeks to get traction and I need to make some progress on my project today.
So, I am looking for some help getting started.
Click HERE To see my simple database schema.
Click HERE to see the vb class that was generated for the schema.
My needs are simple. I have a console app. The main table is the SupplyModel table. Most of the other tables are child tables of the SupplyModel table.
I want to iterate through each of Supply Model records. I want to grab the data for a supply model and then DoStuff with the data. And I also need to iterate through the child records, for each supply model, for example the NumberedInventories and DoStuff with that as well.
I need help doing this in VB rather than C# if possible. I am not looking for the whole solution...if you can supply a couple of code-snippets to get me on my way that would be great.
Thanks for your help.
EDIT
For the record I have already written the following code...
Dim _dataContext As DataContext = New DataContext(ConnectionStrings("SupplyModelDB").ConnectionString)
Dim SMs As Table(Of Data.SupplyModels) = _dataContext.GetTable(Of Data.SupplyModels)()
Dim query = From sm In SMs Where sm.SupplyModelID = 1 Select sm
This code is working...I have a query object and I can use ObjectDumper to enumerate and dump the data...but I still can't figure it out...because ObjectDumper uses reflection and other language constructs I don't get. It DOES enumerate both the parent and child data just like I want (when level=2).
PLEASE HELP...I'M stuck. Help!
Seth
in C# it would be:
var result = from s in _dataContent.SupplyModels where s.SupplyModelID==1 select s;
foreach(SupplyModel item in result)
{
// do stuff
foreach(SupplyModelChild child in item.SupplyModelChilds)
{
//do more stuff on the child
}
}
and a VB.NET version (from the Telerik code converter)
Dim result As var = From s In _dataContent.SupplyModels _
Where s.SupplyModelID = 1 _
Select s
For Each item As SupplyModel In result
' do stuff
'do more stuff on the child
For Each child As SupplyModelChild In item.SupplyModelChilds
Next
Next

Adding related records in LINQ

Processing an XML file with LINQ to add records into a table in a SQL Server database via a data context. As we are adding records we need to assign the parents in various other tables. Most of the time we can find the existing parent and use it but sometimes we will need to create a new parent.
Thought we could do this like this:
Dim defaultPub As publication
defaultPub = New publication With {.name = e..Value}
Dim pub = _Data.publications.Where(Function(s) s.name = e..Value).DefaultIfEmpty(defaultPub).SingleOrDefault
.publication = pub
So we are trying to find a publication that matches e..Value from our XML, but if we can't find one then we use 'defaultPub'. If it does exist though we don't want to add it again. So maybe this approach is flawed anyway even if it did work...
Anyway it's not currently working, we get this error:
Unsupported overload used for query operator 'DefaultIfEmpty'.
The overload requires a publication and is getting one (I've checked the TypeNames in quickwatch), don't know what is going on here.
What we are really looking for is something like the find_or_create from activerecord for Ruby that LINQ seems to be a copied from.
Thanks in advance,
Dave.
OK, I can just do it like this:
Dim pub = _Data.publications.Where(Function(s) s.name = e.<source>.Value).SingleOrDefault
Dim newPub As publication
If Not IsNothing(pub) AndAlso pub.name <> "" Then
.publication = pub
Else
newPub = New publication With {.name = e.<source>.Value}
.publication = newPub
End If
Thanks Val!