Reputation: 11806
I am trying to add a record to my database table using LINQ to SQL and ASP.NET MVC 2.
The snippet in my controller that populates the LINQ object is this:
/* other code removed */
if (ModelState.IsValid)
{
var stream = new Genesis.Domain.Entities.Stream();
// Handle stream
// Is this stream new?
if (form.StreamID == 0)
{
// create new stream
stream.StreamUrl = form.StreamUrl;
stream.StreamName = form.StreamName;
stream.StreamBody = form.StreamBody;
stream.StreamTitle = form.StreamTitle;
stream.StreamKeywords = form.StreamKeywords;
stream.StreamDescription = form.StreamDescription;
form.StreamID = genesisRepository.CreateStream(stream); // CreateStream() returns ID as long
}
/* other code removed */
The genesisRepository.CreateStream()
looks like this:
public partial class SqlGenesisRepository : IGenesisRepository
{
public long CreateStream(Stream stream)
{
streamTable.InsertOnSubmit(stream);
streamTable.Context.SubmitChanges();
return stream.StreamID;
}
}
When genesisRepository.CreateStream()
gets executed, I get this error:
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.NullReferenceException: Object reference not set to an instance of an object.
Source Error:
Line 13: public long CreateStream(Stream stream)
Line 14: {
Line 15: streamTable.InsertOnSubmit(stream);
Line 16: streamTable.Context.SubmitChanges();
Line 17: return stream.StreamID;
Source File: C:\path\to\SqlGenesisRepositoryStreamPartial.cs Line: 15
Stack Trace:
[NullReferenceException: Object reference not set to an instance of an object.]
System.Data.Linq.Mapping.EntitySetDefSourceAccessor`2.GetValue(T instance) +18
System.Data.Linq.Mapping.MetaAccessor`2.GetBoxedValue(Object instance) +47
System.Data.Linq.StandardTrackedObject.HasDeferredLoader(MetaDataMember deferredMember) +106
System.Data.Linq.StandardTrackedObject.get_HasDeferredLoaders() +107
System.Data.Linq.StandardChangeTracker.Track(MetaType mt, Object obj, Dictionary`2 visited, Boolean recurse, Int32 level) +175
System.Data.Linq.StandardChangeTracker.Track(Object obj, Boolean recurse) +83
System.Data.Linq.StandardChangeTracker.Track(Object obj) +12
System.Data.Linq.Table`1.InsertOnSubmit(TEntity entity) +183
Genesis.Domain.Concrete.SqlGenesisRepository.CreateStream(Stream stream) in C:\Documents and Settings\bquakkelaar\Desktop\dropstuff\asp.net mvc\Genesis.0.02\Genesis.Domain\Concrete\SqlGenesisRepositoryStreamPartial.cs:15
Genesis_0_02.Controllers.AdminStreamController.StreamEdit(StreamEditModel form) in C:\Documents and Settings\bquakkelaar\Desktop\dropstuff\asp.net mvc\Genesis.0.02\Genesis.0.02\Controllers\AdminStreamController.cs:107
lambda_method(Closure , ControllerBase , Object[] ) +108
System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters) +51
System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters) +409
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +52
System.Web.Mvc.<>c__DisplayClassd.<InvokeActionMethodWithFilters>b__a() +127
When I put a breakpoint into the function, I see that stream
is not null. Some strings are null. Required strings are not null (IE: streamName = "name") and StreamID is 0
.
Where am I going wrong?
I don't think there is a problem with how I instance streamTable
but seeing as how I out of ideas and most people here think that it's null, here is the code that instances streamTable
.
public partial class SqlGenesisRepository : IGenesisRepository
{
private Table<Stream> streamTable;
public SqlGenesisRepository(string connectionString)
{
streamTable = (new DataContext(connectionString)).GetTable<Stream>();
}
public IQueryable<Stream> Streams { get { return streamTable; } }
}
And the SqlGenesisRepository is instanced in the controller class like this:
public class AdminStreamController : Controller
{
private IGenesisRepository genesisRepository;
public AdminStreamController()
{
//genesisRepository = new FakeGenesisRepository();
genesisRepository = new SqlGenesisRepository(ConfigurationManager.ConnectionStrings["genesis"].ConnectionString);
}
/* rest of code removed for brevity */
}
Upvotes: 0
Views: 1807
Reputation: 11806
Thanks to everyone for the attention to this issue.
It looks like the incorrect code wasn't in any of the code I posted here. I rephrased my question and posted it here: Is there a secret to using LINQ to SQL to add records when the object has relationships?.
The solution can be found there!
Thanks again.
Upvotes: 2
Reputation: 4101
Have you tried explicitly declaring Stream as Genesis.Domain.Entities.Stream ?
As in:
private Table<Genesis.Domain.Entities.Stream> streamTable;
public SqlGenesisRepository(string connectionString)
{
streamTable = (new DataContext(connectionString)).GetTable<Genesis.Domain.Entities.Stream>();
}
Because "Stream" alone could be confusing the compiler, as System.IO.Stream
Also, when you put a breakpoint at
streamTable.InsertOnSubmit(stream);
...to check if streamTable is null, did you check its contents with the debugger? That part where it says "Expanding this item will enumerate ...". It's important because generally it lazy loads, therefore it doesn't go to the DB unless it requires a transaction.
Upvotes: 0
Reputation: 156614
Maybe streamTable is null?
Okay, so based on the stack trace I'm thinking that you may be missing a foreign key constraint. What relationships does a Stream
have? Can you create a new Stream in your database using hand-coded SQL, given only the information that you have in this code?
Upvotes: 0
Reputation: 1423
You don't need to attach the object to the table since the object is new. You just need to InsertOnSubmit.
If you get a null exception after removing that line, your Stream object is likely missing a required field.
Upvotes: 1