2

I want do add my current DbContext to whatever Class I use, for the moment I'm just passing the _context like a common variable.

In this controller example I Pass the _context every time i want to create a Item

[HttpPost("receta/{id}")] [APIauth("medico")] public IActionResult PostItemsReceta(int id, [FromBody]Data[] items) { var tran = _context.Database.BeginTransaction(); //DBB transaction begins try { foreach (Data item in items) new Item(id, item, _context); //I pass the _context like this. tran.Commit(); return Ok(); } catch (Exception e) { tran.Rollback(); return BadRequest("Not inserted!!"); } } 

And in the Class Item I have this

public class Item { [Key] public int id { get; set; } public DateTime? fcaducidad { get; set; } public string nombre { get; set; } public Int32 diagnostico { get; set; } public Item() { } public Item (int receta, Data i, MyDbContext _context) { try { var q = $"EXEC ItemReceta_Insert @idItemFarmacia={i.itemFarmacia.id}" + $", @idDiagnostico={i.diagnostico}, @cantidad={i.cantidad}" + $", @receta={receta}, @posologia='{i.posologia}'"; _context.Database.ExecuteSqlCommand(q); } catch (Exception e) { throw new Exception("Error al insertar ItemReceta", e); } } public static Item[] Report( int receta, MyDbContext _context) { string q = $"EXEC Item_Report @receta={receta}"; return _context.Item.FromSql(q).ToArray(); } } 

I don't want just to have direct access to the context in the controllers because I'm using it many times, I want

new Item(id, item); 

Not

new Item(id, item, _context); Item.Report(bla, _context); new WhatEverClass(name, age, _context); 
4
  • Did you add your MyDbContext in the Startup.cs of your program? I mean _services.AddDbContext<MyDbContext>(......): in ConfigureServices. Commented Sep 13, 2017 at 22:07
  • 4
    Your code has a huge bug with Sql Injection attacks. Any malicious use could potentially do whatever they wanted to your database (at a minimum). Commented Sep 13, 2017 at 22:08
  • Use dependency injection? Then implement CQRS, repository pattern, or whatever you prefer... Commented Sep 13, 2017 at 22:32
  • yes @Steve, I added MyBbContext in the Startup, I'm using it in the controllers. Commented Sep 13, 2017 at 22:55

2 Answers 2

9

I think you aren't really separating your concerns, there's a number of approaches to this, however I'll present a very simple approach to getting things injected into your own classes (I'll leave out some of the properties in your solution to keep it simple ). The main thing you need to do is register your class as a service. So..

first, make your Item a POCO

 public class Item { public int Id { get; set; } } 

now put your Code related to how you are trying to put items in and out of the database into a service, make the constructor take your DbContext so that it will get injected

public class ItemService { private readonly ApplicationContext _context; public ItemService(ApplicationContext context) { _context = context; } public void Add(Item item) { // A paramatized query of some sort to prevent sql injection // see https://learn.microsoft.com/en-us/aspnet/core/data/ef-mvc/advanced var parameters = new List<object>(); _context.Database.ExecuteSqlCommand("", parameters); } } 

now, where you configure your services add your Item Service

public void ConfigureServices(IServiceCollection services) { services.AddDbContext<ApplicationContext>(); services.AddScoped<ItemService>(); } 

now in your controllers constructor say you want the service,

private readonly ItemService _itemService public MyFancyPantsController(ItemService itemService) { _itemService = itemService; } 

now on your post you can access the service

 [Route("post")] [HttpPost()] public IActionResult PostItem() { // construct / deserialize items, then add them... _itemService.Add(new Item()); return Ok(); } 

Now....you may find that you have a lot of Entities ( like Item ) and creating services for them all is a PITA, so you may want are more generic Repository service.

Sign up to request clarification or add additional context in comments.

Comments

-1

Just use using (var db = new DbContext()) { ... } inside your constructor.

This will totally work:

public class AppDbContext : DbContext { public DbSet<Item> Items { get; set; } } public class Data { public int Id { get; set; } public string Value { get; set; } } public class Item { public Item() { } public Item(IEnumerable<Data> data) { Data = data.ToList(); using (var db = new AppDbContext()) { db.Items.Add(this); db.SaveChanges(); } } public override string ToString() { return Data != null ? $"Item:{Id}, Data:{string.Join(',', Data.Select(i => i.Value))}" : $"Item:{Id}, Data:None"; } public int Id { get; set; } public ICollection<Data> Data { get; set; } } 

...

var i1 = new Item(new[] {new Data {Value = "1"}, new Data {Value = "2"}}); var i2 = new Item(new[] {new Data {Value = "3"}, new Data {Value = "4"}}); using (var db = new AppDbContext()) { db.Items.Include(i => i.Data).ToList().ForEach(Console.WriteLine); } 

There are plenty of reasons why this is a bad idea (unable to create items with persisting them, need default constructor anyway for ef, cannot perform bulk inserts easily, high coupling, impossible to test), but it seems like my solution is exactly your solution, so I'm not sure if that helps?

For what its worth note that due to connection pooling it is better and more performant to create a new DbContext with:

using (var db = new AppDbContext()) { ... } 

Than it is to have a singleton object that you pass around manually or using DI; this is because the context internally caches query results, and you're basically having a slow memory leak if you use it as a singleton.

ie. This: public Item (int receta, Data i, MyDbContext _context) is actually tangibly worse than several using (var db = new AppDbContext() { ... } unless you're specifically using the result cache.

1 Comment

var db = new AppDbContext() will not work because AppDbContext does NOT have default constructor.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.