0

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:

Updated to more accurate error and stacktrace

    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?

Edit: How `streamTable` is instanced

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 */
}
quakkels
  • 11,676
  • 24
  • 92
  • 149

4 Answers4

2

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.

Community
  • 1
  • 1
quakkels
  • 11,676
  • 24
  • 92
  • 149
1

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.

esteuart
  • 1,323
  • 1
  • 11
  • 14
  • If I have `public EntitySet ...etc...` in the `Stream` object, is that considered a property that is required? – quakkels Oct 06 '10 at 17:08
0

Maybe streamTable is null?

Edit

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?

Community
  • 1
  • 1
StriplingWarrior
  • 151,543
  • 27
  • 246
  • 315
  • Thanks for the idea. I have `streamTable` defined in another partial class (same class of course) this way: `private Table streamTable;` – quakkels Oct 06 '10 at 16:05
  • Oh... and I have gotten update functionality working... it's just this create functionality that is somehow hanging up. – quakkels Oct 06 '10 at 16:06
  • Your definition doesn't automatically initialize streamTable. Have you actually checked that streamTable is not null that this point in time? – StriplingWarrior Oct 06 '10 at 16:14
  • The definition does set `streamTable`. Notice the code I posted was a partial definition. – quakkels Oct 06 '10 at 16:37
  • I'll try to create a new Stream with hand coded sql. I do have foreign key relationships... two of them. – quakkels Oct 06 '10 at 17:22
  • I successfully executed `INSERT INTO genesis.dbo.Stream (StreamName, StreamUrl) VALUES ('Name', 'url');` in SQL Server Management Studio. – quakkels Oct 06 '10 at 17:33
  • I tried running `streamTable.Context.ExecuteCommand("INSERT INTO genesis.dbo.Stream (StreamName, StreamUrl) VALUES ('Name', 'url');");' in the repository instead of `streamTable.InsertOnSubmit()` and i got an error that said `Value cannot be null. Parameter name: source`. – quakkels Oct 06 '10 at 17:37
  • It sounds like there may be some kind of problem with the way you're connecting. Are you using the same login credentials with SQL Server Management Studio as are specified in your connection string? – StriplingWarrior Oct 06 '10 at 17:51
  • Just out of curiosity, rather than using the streamTable field, try `using(var context = (new DataContext(connectionString)) {...}` inside the `CreateStream` method, and getting a table off of that data context. I don't know if this will do anything, but using a shorter-lived context might simplify things. – StriplingWarrior Oct 06 '10 at 17:56
  • I know that the connection is good because I can update existing records using that connection string. – quakkels Oct 06 '10 at 18:28
  • Stream has two EntitySet properties which are null when I try to create a new record. Is there a way to instanciate those two properties? When I try stream.StreamEntry = new EntitySet(); I get an error inside the Stream object – quakkels Oct 06 '10 at 18:51
  • UPDATE: even though I got an error for `streamTable.Context.ExecuteCommand("INSERT INTO genesis.dbo.Stream (StreamName, StreamUrl) VALUES ('Name', 'url');");` it still successfully updated the database – quakkels Oct 06 '10 at 19:35
  • 1
    If you were able to create the object with a plain SQL statement, I don't think you should have to do anything with the EntitySets to make them work. However, I've worked pretty much exclusively with the Entity Framework, so I don't know for sure. Based on http://stackoverflow.com/questions/499436/linq-insertonsubmit-nullreferenceexception/499622#499622, I am led to believe that the entity sets should be instantiated by the auto-generated constructor, though. So they shouldn't ever be null. Are you messing with the `Stream`'s constructors or anything? – StriplingWarrior Oct 06 '10 at 19:40
  • ?? The auto-generated constructor ?? So I shouldn't do this: `Stream stream = new Stream();` in my controller? – quakkels Oct 06 '10 at 20:04
  • btw: as this question has gotten very long, I have refined my question and posted it here: http://stackoverflow.com/questions/3876360/is-there-a-secret-to-using-linq-to-sql-to-add-records-when-the-object-has-relatio – quakkels Oct 06 '10 at 20:05
  • LINQ to SQL automatically generates a constructor for each object Type in your context. So if you find the definition of the constructor you're calling when you say `new Stream()`, it should have statements that populate the entity sets and otherwise initialize the Stream object. – StriplingWarrior Oct 06 '10 at 20:13
  • I am hand coding all the linq objects per Steven Sanderson's book: Pro ASP.NET MVC 2 Framework. I don't know how to do it any other way... yet. – quakkels Oct 06 '10 at 20:16
0

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.

Francisco
  • 4,104
  • 3
  • 24
  • 27
  • Thanks for the suggestion. But, I am 100% sure that `streamTable` is defined correctly. I will try your suggestion, but I'm sure that the compiler understands which stream I mean because I am not `using System.IO.Stream;` on the class. – quakkels Oct 06 '10 at 19:37
  • Tried `` with no change in behavior. – quakkels Oct 06 '10 at 19:39