Reputation: 1307
I'm new to MVC & .net core so I'm not sure how to resolve this in my particular case. The telerik example is overly complex I feel, but perhaps I'm not understanding something I should.
I'm trying to get the Telerik Treelist control to work: https://demos.telerik.com/aspnet-core/treelist/editing.
My table OrgStructures
is a self referencing table with OrgId
and ParentId
I want to select data from my table OrgStructures
using a simple LINQ command but I'm facing an error and I don't know where to start, but I suspect the dbcontext (ITContext
) is incorrect.
What works is there are other controllers in my app that works fine, but it's structured differently from the Telerik example.
What works:
namespace IT.Web.Controllers
{
[BreadCrumb(Title = "User Management", UseDefaultRouteUrl = true, Order = 0)]
public class UserController : BaseController
{
public UserController(ITContext dbContext, IConfiguration config) : base(dbContext, config)
{
}
public IActionResult Index()
{
UsersViewModel usersVm = new UsersViewModel();
LoadItemLists(usersVm);
if (!_sessionUser.IsApplicationAdministrator)
{
usersVm.Roles.Remove(usersVm.Roles.Where(o => o.Value == OCWebHelper.Role.ApplicationAdministrator.ToString()).FirstOrDefault());
}
return View(usersVm);
}
public IActionResult GetAllForGroup([DataSourceRequest] DataSourceRequest request, int groupId)
{
var users = _db.GroupUsers
.Where(o => o.GroupUserId == groupId)
.Include(o => o.User)
.OrderBy(o => o.User.LastName).ThenBy(o => o.User.FirstName)
.Select(o =>
new UserViewModel
{
Id = o.User.Id,
LastName = o.User.LastName,
FirstName = o.User.FirstName,
Username = o.User.Username,
Email = o.User.Email
});
return Json(users.ToDataSourceResult(request));
}
My appsettings.json:
"ConnectionStrings": {
"DefaultConnection": "Data Source=1.11.11.1;Initial Catalog=MyDB;Persist Security Info=True;User ID=MyID;Password=MyPW"
},
My action(What doesn't work):
public virtual IList<OrgStructureModel> GetAll()
{
using (var db = GetContext())
{
var result = Session.GetObjectFromJson<IList<OrgStructureModel>>("OrgStructure");
if (result == null || UpdateDatabase)
{
result = db.OrgStructures
.ToList()
.Select(org => org.ToOrgStructureModel(db.OrgStructures.Where(s => s.ParentId == org.OrgId).Count() > 0))
.ToList();
Session.SetObjectAsJson("OrgStructure", result);
}
return result;
}
}
The Error:
No database provider has been configured for this DbContext. A provider can be configured by overriding the DbContext.OnConfiguring method or by using AddDbContext on the application service provider. If AddDbContext is used, then also ensure that your DbContext type accepts a DbContextOptions object in its constructor and passes it to the base constructor for DbContext.
My DB Context:
public partial class ITContext : DbContext
{
public ITContext()
{
}
public ITContext(DbContextOptions<ITContext> options)
: base(options)
{
}
public virtual ITContext GetContext()
{
return new ITContext();
}
public virtual DbSet<OrgStructure> OrgStructures { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasAnnotation("ProductVersion", "2.2.0-rtm-35687");
modelBuilder.Entity<GroupUser>(entity =>
{
entity.Property(e => e.CreatedDate)
.HasColumnType("datetime")
.HasDefaultValueSql("(getdate())");
entity.HasOne(d => d.GroupUserNavigation)
.WithMany(p => p.GroupUserGroupUserNavigations)
.HasForeignKey(d => d.GroupUserId)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_GroupUsers_Users1");
entity.HasOne(d => d.User)
.WithMany(p => p.GroupUserUsers)
.HasForeignKey(d => d.UserId)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_GroupUsers_Users");
});
modelBuilder.Entity<OrgStructure>(entity =>
{
entity.ToTable("OrgStructure");
entity.HasKey(e => e.OrgId);
entity.Property(e => e.Name)
.HasColumnType("VARCHAR(50)")
.HasDefaultValueSql("NULL");
entity.Property(e => e.Acronym)
.HasColumnType("VARCHAR(10)")
.HasDefaultValueSql("NULL");
entity.Property(e => e.DepartmentCode)
.HasColumnType("VARCHAR(4)")
.HasDefaultValueSql("NULL");
entity.Property(e => e.ParentId)
.HasColumnType("INT")
.HasDefaultValueSql("NULL");
entity.HasOne(d => d.ReportsToNavigation).WithMany(p => p.InverseReportsToNavigation).HasForeignKey(d => d.ParentId);
});
OnModelCreatingPartial(modelBuilder);
}
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
My startup.cs:
services.AddDbContext<ITContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
My OrgStructureController:
namespace IT.Web.Controllers
{
public partial class OrgStructureController : Controller
{
private IOrgStructureService orgStructure;
public OrgStructureController(
IOrgStructureService service)
{
orgStructure = service;
}
public ActionResult Index()
{
return View();
}
public JsonResult All([DataSourceRequest] DataSourceRequest request)
{
var result = GetDirectory().ToTreeDataSourceResult(request,
e => e.OrgId,
e => e.ParentId,
e => e
);
return Json(result);
}
public JsonResult Destroy([DataSourceRequest] DataSourceRequest request, OrgStructureModel org)
{
if (ModelState.IsValid)
{
orgStructure.Delete(org, ModelState);
}
return Json(new[] { org }.ToTreeDataSourceResult(request, ModelState));
}
public JsonResult Create([DataSourceRequest] DataSourceRequest request, OrgStructureModel org)
{
if (ModelState.IsValid)
{
orgStructure.Insert(org, ModelState);
}
return Json(new[] { org }.ToTreeDataSourceResult(request, ModelState));
}
public JsonResult Update([DataSourceRequest] DataSourceRequest request, OrgStructureModel org)
{
if (ModelState.IsValid)
{
orgStructure.Update(org, ModelState);
}
return Json(new[] { org }.ToTreeDataSourceResult(request, ModelState));
}
private IEnumerable<OrgStructureModel> GetDirectory()
{
return orgStructure.GetAll();
}
}
}
My OrgStructureService:
namespace IT.Web.Services
{
using System.Linq;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.EntityFrameworkCore;
using IT.Web.Models;
using IT.Data.Models;
using Microsoft.AspNetCore.Http;
using System.Collections.Generic;
public static class OrgStructureIEnumerableExtensions
{
public static OrgStructureModel ToOrgStructureModel(this OrgStructure org, bool hasChildren)
{
return new OrgStructureModel
{
OrgId = org.OrgId,
ParentId = org.ParentId,
Name = org.Name,
DepartmentCode = org.DepartmentCode,
Acronym = org.Acronym,
hasChildren = hasChildren
};
}
}
public class OrgStructureService : ITContext, IOrgStructureService
{
private static bool UpdateDatabase = false;
private ISession _session;
public ISession Session { get { return _session; } }
public OrgStructureService(IHttpContextAccessor httpContextAccessor)
{
_session = httpContextAccessor.HttpContext.Session;
}
public virtual IList<OrgStructureModel> GetAll()
{
using (var db = GetContext())
{
var result = Session.GetObjectFromJson<IList<OrgStructureModel>>("OrgStructure");
if (result == null || UpdateDatabase)
{
result = db.OrgStructures
.ToList()
.Select(org => org.ToOrgStructureModel(db.OrgStructures.Where(s => s.ParentId == org.OrgId).Count() > 0))
.ToList();
Session.SetObjectAsJson("OrgStructure", result);
}
return result;
}
}
public virtual void Insert(OrgStructureModel org, ModelStateDictionary modelState)
{
if (!UpdateDatabase)
{
var orgs = GetAll();
var first = orgs.OrderByDescending(e => e.OrgId).FirstOrDefault();
var id = (first != null) ? first.OrgId : 0;
org.OrgId = id + 1;
orgs.Insert(0, org);
Session.SetObjectAsJson("OrgStructure", orgs);
}
else
{
using (var db = GetContext())
{
var entity = org.ToEntity();
db.OrgStructures.Add(entity);
db.SaveChanges();
org.OrgId = entity.OrgId;
}
}
}
public virtual void Update(OrgStructureModel org, ModelStateDictionary modelState)
{
if (!UpdateDatabase)
{
var orgs = GetAll();
var target = orgs.FirstOrDefault(e => e.OrgId == org.OrgId);
if (target != null)
{
target.Name = org.Name;
target.Acronym = org.Acronym;
target.DepartmentCode = org.DepartmentCode;
target.ParentId = org.ParentId;
}
Session.SetObjectAsJson("OrgStructure", orgs);
}
else
{
using (var db = GetContext())
{
var entity = org.ToEntity();
db.OrgStructures.Attach(entity);
db.Entry(entity).State = EntityState.Modified;
db.SaveChanges();
}
}
}
public virtual void Delete(OrgStructureModel org, ModelStateDictionary modelState)
{
if (!UpdateDatabase)
{
var orgs = GetAll();
var target = orgs.FirstOrDefault(e => e.OrgId == org.OrgId);
if (target != null)
{
DeleteSessionChildren(target, orgs);
orgs.Remove(target);
}
Session.SetObjectAsJson("OrgStructure", orgs);
}
else
{
using (var db = GetContext())
{
var entity = org.ToEntity();
db.OrgStructures.Attach(entity);
DeleteEntityChildren(entity);
db.SaveChanges();
}
}
}
private void DeleteEntityChildren(OrgStructure org)
{
using (var db = GetContext())
{
var children = db.OrgStructures.Where(e => e.ParentId == org.OrgId);
foreach (var subordinate in children)
{
DeleteEntityChildren(subordinate);
}
db.OrgStructures.Remove(org);
}
}
private void DeleteSessionChildren(OrgStructureModel org, IList<OrgStructureModel> orgs)
{
var subordinates = orgs.Where(m => m.ParentId == org.OrgId).ToList();
foreach (var subordinate in subordinates)
{
DeleteSessionChildren(subordinate, orgs);
orgs.Remove(subordinate);
}
}
}
}
My view:
@model IT.Web.Models.OrgStructureModel
@{
ViewData["Title"] = "Org Structure";
}
@(Html.Kendo().TreeList<IT.Data.Models.OrgStructure>()
.Name("treelist")
.Toolbar(toolbar => toolbar.Create())
.Columns(columns =>
{
columns.Add().Field(e => e.Name).Width(220);
columns.Add().Field(e => e.Acronym).Width(100);
columns.Add().Field(e => e.DepartmentCode);
columns.Add().Width(300).Command(c =>
{
c.CreateChild().Text("Add child");
c.Edit();
c.Destroy();
})
.HtmlAttributes(new
{
style = "text-align: center;"
});
})
.Editable()
.Sortable()
.Filterable()
.DataSource(dataSource => dataSource
.Create(create => create.Action("Create", "OrgStructure"))
.Read(read => read.Action("All", "OrgStructure"))
.Update(update => update.Action("Update", "OrgStructure"))
.Destroy(delete => delete.Action("Destroy", "OrgStructure"))
.Model(m =>
{
m.Id(f => f.OrgId);
m.ParentId(f => f.ParentId);
m.Expanded(true);
m.Field(f => f.Name);
m.Field(f => f.Acronym);
m.Field(f => f.ParentId);
m.Field(f => f.DepartmentCode);
})
)
.Height(540)
)
<style>
.k-treelist .k-command-cell .k-button {
min-width: 0px;
padding: 10px 10px 10px 10px;
}
</style>
My IOrgStructureService:
namespace IT.Web.Services
{
public interface IOrgStructureService
{
IList<OrgStructureModel> GetAll();
void Insert(OrgStructureModel org, ModelStateDictionary modelState);
void Update(OrgStructureModel org, ModelStateDictionary modelState);
void Delete(OrgStructureModel org, ModelStateDictionary modelState);
}
}
It looks like the coding structure in the app is very different from the Telerik example since the Telerik has an additional Service layer which is confusing to a beginner to get to work within the current app structure. I've traced the error and the OrgStructure
table query is empty.
Any help is appreciated, thanks!
Upvotes: 0
Views: 492
Reputation: 239380
Your OrgStructureService
inherits from your ITContext
, but it does not implement any constructor that allows DbContextOptionsBuilder
to be passed in. As a result, any time this service is injected, the internal database connection is not setup up, and hence your error.
You'd need to alter your constructor like:
public class OrgStructureService : ITContext, IOrgStructureService
{
...
public OrgStructureService(DbContextOptionsBuilder builder, IHttpContextAccessor httpContextAccessor)
: base(builder)
{
_session = httpContextAccessor.HttpContext.Session;
}
However, this is an extremely poor design over all. If anything, this service should take the context as a dependency, not inherit from the context:
public class OrgStructureService : IOrgStructureService
{
private readonly ITContext _context;
private readonly ISession _session;
public OrgStructureService(ITContext context, IHttpContextAccessor httpContextAccessor)
{
_context = context;
_session = httpContextAccessor.HttpContext.Session;
}
Upvotes: 1