DbContext not updating database

.net-core c# dbcontext entity-framework-core

Question

When I save changes to DbContext, it doesn't update my database. No errors either.

Yes, the incoming form data is filled. Yes, the connection string is correct, I know this because I'm able to retrieve data from the database perfectly fine. If it's of relevance, it's a many-to-many relationship.

A roadmap is like an article as far as you're concerned which can be associated with many tags.

    public static class RoadmapService
    {
        static ConkerDbEntities dbContext;
        public static void createDbContext(ConkerDbEntities _dbContext)
        {
            dbContext = _dbContext;
        }

        public static void addToDatabase(Form form)
        {
            Roadmaps roadmap = new Roadmaps { RoadmapTitle = form.title, 
                                              RoadmapSummary = form.summary, 
                                              RoadmapBody = form.body };

            var tags = new Tags[form.tags.Length];

            for(int i = 0; i < tags.Length; i++)
            {
                tags[i] = new Tags();
                tags[i].TagId = form.tags[i];
            }

            var roadmapTags = new RoadmapTags[form.tags.Length];

            for(int i = 0; i < tags.Length; i++)
            {
                roadmapTags[i] = new RoadmapTags{Roadmap = roadmap, Tag = tags[i]};
            }

            dbContext.AddRange(roadmapTags);
            dbContext.SaveChangesAsync();
        }
    }
}

Where dbcontext is created, this is the constructor of Startup.cs

        public static SearchEngine engine;
        public static ConkerDbEntities dbContext;

        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;

            dbContext = new ConkerDbEntities();

            RoadmapService.createDbContext(dbContext);
            engine = new SearchEngine(dbContext);

        }

I get no errors, and there's nothing added to the database. I'm probably doing something fundamentally wrong here. Thanks in advance.

1
0
5/28/2019 9:36:26 PM

Accepted Answer

You are using async programming, but your method is not async.

use dbContext.SaveChangesAsync(); when you have async methods, use dbContext.SaveChanges(); when is not async.

Also, you are using static classes, this should not be the case if you are using dependency injection. DI will handle the life cycle of your objects.

Your class is not defined as should be, you have some format errors, and should look something like this:

public class RoadmapService
{
    private readonly ConkerDbEntities _dbContext;

    public RoadmapService(ConkerDbEntities dbContext)
    {
        _dbContext = dbContext;
    }

    public async Task AddToDatabase(Form form)
    {
        Roadmaps roadmap = new Roadmaps {
            RoadmapTitle = form.title, 
            RoadmapSummary = form.summary, 
            RoadmapBody = form.body 
        };

        var tags = new Tags[form.tags.Length];

        for(int i = 0; i < tags.Length; i++)
        {
            tags[i] = new Tags();
            tags[i].TagId = form.tags[i];
        }

        var roadmapTags = new RoadmapTags[form.tags.Length];

        for(int i = 0; i < tags.Length; i++)
        {
            roadmapTags[i] = new RoadmapTags{Roadmap = roadmap, Tag = tags[i]};
        }

        _dbContext.AddRange(roadmapTags);
        _dbContext.SaveChangesAsync();
    }
}

Then in your controller you can use your service as is

public class OrdersController : Controller
{
    private readonly RoadmapService _roadmapService;

    public OrdersController(RoadmapService roadmapService)
    {
        _roadmapService = roadmapService;
    }

    [HttpGet]
    [Route("api/[controller]/{folio}")]
    public async Task<IActionResult> Status(string folio)
    {
        await _roadmapService.AddToDatabase(something);
        return Ok();
    }
}

I also would recommend to study about linq and how you can avoid those foreach cycles using select, check the default net core coding standards.

Edit

I'm curious, would LINQ provide any performance benefits in this case vs just a regular for loop?

It is more about the readability and maintainability of your code, in the answer I already put a link to a post where is better explained, you are creating technical debt in your code, you are initializing arrays and filling them, handling indices and more... , but it reduces to this:

What is more easy to read? this:

public async Task AddToDatabase(Form form)
{
    Roadmaps roadmap = new Roadmaps {
        RoadmapTitle = form.title, 
        RoadmapSummary = form.summary, 
        RoadmapBody = form.body 
    };

    var tags = new Tags[form.tags.Length];

    for(int i = 0; i < tags.Length; i++)
    {
        tags[i] = new Tags();
        tags[i].TagId = form.tags[i];
    }

    var roadmapTags = new RoadmapTags[form.tags.Length];

    for(int i = 0; i < tags.Length; i++)
    {
        roadmapTags[i] = new RoadmapTags{Roadmap = roadmap, Tag = tags[i]};
    }

    _dbContext.AddRange(roadmapTags);
    _dbContext.SaveChangesAsync();
}

or this

    public async Task AddToDatabase(Form form)
    {
        var roadmap = new Roadmap {
            RoadmapTitle = form.title, 
            RoadmapSummary = form.summary, 
            RoadmapBody = form.body 
        };

        var roadmapTags = form.Tags
            .Select(tagId => new Tag        // First we take our form.tags and convert it to Tag objects
            {
                TagId = tagId
            })
            .Select(tag => new RoadmapTags  // Then we take the result of the previous conversion and we 
            {                               // transform again to RoadmapTags, we even could do this in one pass
                Roadmap = roadmap,          // but this way is more clear what the transformations are
                Tag = tag
            })
            .ToList();

        _dbContext.AddRange(roadmapTags);
        await _dbContext.SaveChangesAsync();
    }

If you just started learning programming, you could ignore this until you are more confortable with the for, foreach, while and other control structures. This is structure programming, and it is a topic by itself.

Also how would I pass the roadmapService object to the Controller constructor, I've just never seen that.

That is the magic of dependency injection, just let the system create the object for you, you just have to ask for the type.

This is also a big topic, you should check my previous link to the microsoft documentation, but basically, all you have to do is to define classes as dependencies, so, when you ask for one, the system itself check the dependencies, and the dependencies of that objects, until resolves all the tree of dependencies.

With this, if you need one more dependency latter in your class, you can add directly but you do not need to modify all the classes that uses that class.

To use this in the controller, please check the official docs, you just have to add you dependencies to the constructor, and win!, basically two parts:

Add in your Startup.class

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddTransient<MySpecialClassWithDependencies>();
    ...
}

Then in your controller:

public class HomeController : Controller
{
    private readonly MySpecialClassWithDependencies _mySpecialClassWithDependencies;

    public HomeController(MySpecialClassWithDependencies mySpecialClassWithDependencies)
    {
        _mySpecialClassWithDependencies = mySpecialClassWithDependencies;
    }

    public IActionResult Index()
    {
        // Now i can use my object here, the framework already initialized for me!
        return View();
    }
2
5/29/2019 12:08:30 AM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow