我是MVC和.net核心的新手,所以我不确定如何解决我的特殊情况。我觉得telerik的例子太复杂了,但是也许我不明白我应该做的事情。
我正在尝试使Telerik Treelist控件正常工作:https://demos.telerik.com/aspnet-core/treelist/editing。
我的表OrgStructures
是一个自引用表,其中包含OrgId
和ParentId
我想使用一个简单的LINQ命令从表OrgStructures
中选择数据,但是遇到错误,我不知道从哪里开始,但是我怀疑dbcontext(ITContext
)不正确。
有效的是我的应用程序中还有其他控制器可以正常工作,但是其结构与Telerik示例不同。
有效的方法:
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));
}
我的appsettings.json:
"ConnectionStrings": {
"DefaultConnection": "Data Source=1.11.11.1;Initial Catalog=MyDB;Persist Security Info=True;User ID=MyID;Password=MyPW"
},
我的动作(无效):
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;
}
}
错误:
尚未为此DbContext配置数据库提供程序。一种 可以通过重写DbContext.OnConfiguring来配置提供程序 方法或通过在应用程序服务提供程序上使用AddDbContext。 如果使用AddDbContext,则还要确保您的DbContext类型 在其构造函数中接受DbContextOptions对象,并 将其传递给DbContext的基本构造函数。
我的数据库上下文:
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);
我的startup.cs:
services.AddDbContext<ITContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
我的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();
}
}
}
我的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);
}
}
}
}
我的观点:
@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>
我的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);
}
}
该应用程序中的编码结构似乎与Telerik示例完全不同,因为Telerik具有一个附加的Service层,这会使初学者感到困惑,无法在当前的应用程序结构中使用它。我已跟踪该错误,并且OrgStructure
表查询为空。
感谢您的帮助,谢谢!
答案 0 :(得分:1)
您的String url = "https://keycloakserver:8888/auth/realms/testrealm/protocol/openid-connect/token";
ClientCredentialsResourceDetails resourceDetails = new ClientCredentialsResourceDetails();
resourceDetails.setGrantType(OAuth2Constants.CLIENT_CREDENTIALS);
resourceDetails.setAccessTokenUri(url);
resourceDetails.setClientId("your-micro-service-client-id");
resourceDetails.setClientSecret("p455word");
RestTemplate restTemplate = new OAuth2RestTemplate(resourceDetails);
继承自您的OrgStructureService
,但未实现任何允许ITContext
传入的构造函数。因此,每次注入此服务时,内部数据库连接未建立,因此出现错误。
您需要像下面那样更改构造函数:
DbContextOptionsBuilder
但是,这是一个极其的糟糕设计。如果有的话,此服务应将上下文作为依赖项,而不是从上下文继承:
public class OrgStructureService : ITContext, IOrgStructureService
{
...
public OrgStructureService(DbContextOptionsBuilder builder, IHttpContextAccessor httpContextAccessor)
: base(builder)
{
_session = httpContextAccessor.HttpContext.Session;
}