I have a section of code in my MVC controller that works fine during run-time, but during testing fails. I do a call to the context with an include. During run-time, I can check thisCall and see that thisCall.CallForContentCustomForm is not null. But debugging during testing, it is null.
My models:
public partial class CustomForm : BaseEntity
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid CustomFormId { get; set; }
//...
}
public class CallForContent : BaseEntity
{
[Key, ForeignKey("CallForContentResource"), DatabaseGenerated(DatabaseGeneratedOption.None)]
public Guid CallForContentId { get; set; }
//...
public Guid CallForContentFormId { get; set; }
[ForeignKey("CallForContentFormId")]
public CustomForm CallForContentCustomForm { get; set; }
}
In my controller:
public partial class ProjectController : BaseController
{
private IMkpContext db;
#region "Constructor"
public ProjectController()
{
db = new MkpContext();
}
public ProjectController(IMkpContext dbContext)
{
db = dbContext;
}
#endregion
public virtual ActionResult callforcontentedit(Guid? id)
{
var thisCall =
db.CallForContent
.Include(cfc => cfc.CallForContentCustomForm)
.Include(cfc => cfc.Project)
.FirstOrDefault(cfc => cfc.CallForContentId == id);
// At this point during run-time thisCall.CallForContentCustomForm has a value,
// but is null during testing
// This row does return the expected result during testing.
var customForms = db.CustomForms.Where(c => c.IsActive && c.CustomFormId == thisCall.CallForContentFormId);
if (thisCall == null) return RedirectToAction("Index", "Submission");
var viewModel = Mapper.Map<CallForContentViewModel>(thisCall);
// ...
ViewBag.Title = viewModel.CallForContentCustomForm.FormName; // Fails here during tests
}
}
In my testing setup, I do add data to the FakeDbContext for the CustomForm table.
var newCallForContentForm = FakeCallForContentForm(newProfile.ProfileId);
fakeDb.CustomForms.Add(newCallForContentForm);
//...
var newCallForContentProposalForm = FakeCallForContentProposalForm(newProfile.ProfileId);
fakeDb.CustomForms.Add(newCallForContentProposalForm);
My Test:
[TestMethod]
public void Project_CallForContent_Test()
{
// Arrange
var fakeDb = TestFakes.SetupFakeDbContext();
var controller = TestFakes.ProjectController(fakeDb);
// Act
var result = controller.callforcontentedit(fakeDb.CallForContent.FirstOrDefault().CallForContentId) as ViewResult;
// Assert
Assert.IsNotNull(result);
}
Here is what my context looks like:
public class FakeMkpContext : AuditDbContext, IMkpContext
{
#region Constructors
static FakeMkpContext()
{
Database.SetInitializer<FakeMkpContext>(null);
}
public FakeMkpContext() : base("Name=FakeMkpContext")
{
this.Profile = new FakeProfileSet();
}
#endregion
#region Property (Dbset)
public IDbSet<Address> Address { get; set; }
public IDbSet<Keyword> Keyword { get; set; }
public IDbSet<CustomForm> CustomForms { get; set; }
public IDbSet<SubmittedForm> SubmittedForms { get; set; }
public IDbSet<SubmittedFormData> SubmittedFormData { get; set; }
public IDbSet<Project> Project { get; set; }
public IDbSet<ProjectType> ProjectType { get; set; }
public IDbSet<CustomFieldGroup> CustomFieldGroup { get; set; }
public IDbSet<CustomFormGroup> CustomFormGroup { get; set; }
public IDbSet<CallForContent> CallForContent { get; set; }
#endregion
//...
}
I am not using Moq for the entity framework portion of my tests.
Related
I'm trying to build a REST API. I have been using this guide by Microsoft Docs and I'd appreciate some help.
I have 2 models Library and Book. Each have their own controllers as well.
I want each to reference each other so I can get all books within a library and I want a book to reference what library it belongs to. I am using an in-memory database by Microsoft Entity Framework
My current model classes look like this:
Library:
public class Library
{
[Key]
public long id { get; set; }
public Book[] bookArray { get; set; }
public string postalCode { get; set; }
public string street { get; set; }
public string city { get; set; }
public string country { get; set; }
}
Book:
public class Book
{
[Key]
public long id { get; set; }
public long libraryId { get; set; }
public string title { get; set; }
public string author { get; set; }
public string description { get; set; }
}
I want a GET endpoint like so "api/Libraries/{id}/books" that will return the array of books within a library as JSON, but I can't return the array. I get the error "Can't implicitly convert Models.Book to Microsoft.AspNetCore.Mvc.ActionResult<A2.Models.Library>". Have I setup the model classes correctly? and how do I resolve this error.
The Code:
// GET: api/Libraries/5/books
[HttpGet("{id}/books")]
public async Task<ActionResult<Library>> GetLibraryBooks(long id)
{
var library = await _context.Libraries.FindAsync(id);
if (library == null)
{
return NotFound();
}
return library.bookArray;
}
Your Method should return Book[] like this:
[HttpGet("{id}/books")]
public async Task<ActionResult<Book[]>> GetLibraryBooks(long id)
{
var library = await _context.Libraries.FindAsync(id);
if (library == null)
{
return NotFound();
}
return Ok(library.bookArray);
}
UPDATE
public class Library
{
public Libary(){
books = new List<Book>();
}
[Key]
public long id { get; set; }
public List<Book> books { get; set; }
public string postalCode { get; set; }
public string street { get; set; }
public string city { get; set; }
public string country { get; set; }
}
UPDATE 2
public class LibraryController : Controller
{
private readonly LibraryContext _context;
public LibraryController(LibraryContext context)
{
_context = context;
}
[HttpPost("{id}")]
public IActionResult AddBookToLibrary([FromRoute]long id ,[FromBody] Book bookToAdd)
{
var libraryToAddBook = _context.Libraries.Include(l => l.books)
.FirstOrDefault(l => l.id == id);
if (libraryToAddBook == null)
return NotFound();
libraryToAddBook.books.Add(bookToAdd);
_context.SaveChanges();
return Ok();
}
}
UPDATED CONTEXT
public class LibraryContext : DbContext
{
public LibraryContext(DbContextOptions<LibraryContext> options)
: base(options)
{
}
public DbSet<Library> Libraries { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Library>()
.OwnsMany<Book>(l => l.books);
}
}
startup.cs
var connectionString = Configuration.GetConnectionString("myDatabaseConnectionString");
services.AddDbContext<LibraryContext>(options =>
{
//options.USEYOURDATABASE(connectionString); //you might need install a NuGet eg. Microsoft.EntityFrameworkCore.SqlServer
});
I grouped my data and I want to send this data to the view with the model. How can I write property into the viewmodel
WorkPlan Class
public class WorkPlan:IEntity
{
public int WorkPlanId { get; set; }
public int PlanNumber { get; set; }
public string Day { get; set; }
public string Lesson { get; set; }
public string Description { get; set; }
public bool IsActive { get; set; }
}
WorkPlanViewModel
public class WorkPlanViewModel:BaseViewModel
{
public List<WorkPlan> WorkPlans { get; set; }
public WorkPlan WorkPlan { get; set; }
}
Action
public IActionResult Index()
{
WorkPlanViewModel model=new WorkPlanViewModel();
model.Message=new Message();
var allWorkPlan = workPlanService.GetAll();
var groupPlan = allWorkPlan.GroupBy(p => p.PlanNumber)
.Select(p => new {PlanNumber=p.Key, Day= p.GroupBy(b => b.Day).ToList() } ).ToList();
return View(model);
}
groupPlan is my grouped data
You could create a class that reflects that anonymous type and add it as a property to your view model.
Controller/Action Code - note the new GroupPlan code below in the Select
var vm = new MyViewModel();
vm.GroupPlans = allWorkPlan.GroupBy(p => p.PlanNumber)
.Select(p => new GroupPlan { PlanNumber = p.Key, Day = p.GroupBy(b => b.Day).ToList() }).ToList();
GroupPlan Class
public class GroupPlan
{
public int PlanNumber { get; set; }
public List<IGrouping<string, WorkPlan>> Day { get; set; }
}
ViewModel Class
public class MyViewModel
{
public List<GroupPlan> GroupPlans { get; set; }
}
I would like to have a common class for my business layers (BL) which has a method convert IQueryable to IQueryable.
- efo: Entity Framework object
- bo: business object
I'm using Entity Framework Core.
public partial class Language //EF object
{
public long Id { get; set; }
public string Code { get; set; }
public string Name { get; set; }
public string Image { get; set; }
public virtual ICollection<News> News { get; set; }
}
public class BOLanguage //Business object
{
public string Name { get; set; }
public string Image { get; set; }
}
public class BL<efo, bo>
where efo : class, new()
where bo : class, new()
{
public Context context;
public BL()
{
context = new Context();
}
public IQueryable<bo> SelectAll()
{
IQueryable<efo> query = context.Set<efo>();
return query.Select(x => new bo
{
//TODO: I don't know how to do here
});;
}
//public IQueryable<BOLanguage> SelectAll() //example
//{
// return context.Language.Select(x => new BOLanguage
// {
// Name = x.Name,
// Image = x.Image
// });
//}
}
Thank you. Hope you understand.
For my Project I want to access the database but I have no clue because it is my first time programming with ASP.net mvc.
I have already read through a bunch of guides but to no avail.
Controller
This right here is my controller which gets a Code from a Machine (e.g.: 123456) but when I want to access the database through this option I get the No database provider has been configured for this DbContext. Error Message.
namespace Qualitätskontrolle.Controllers
{
public class HomeController : Controller
{
[HttpGet]
public IActionResult StartPage(string Code)
{
Debug.WriteLine(Code);
ApplicationDbContext dbContext = new ApplicationDbContext(.);
var dbErgebnisse = dbContext.Result.ToList();
for (int i = 0; i < dbErgebnisse.Count; i++)
{
Debug.WriteLine(dbErgebnisse[i]);
}
return View();
}
}
Context Class
I have read that the empty constructor should be removed but then I cannot access it in the Controller class.
namespace Qualitätskontrolle.Data
{
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext()
{
}
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<Bilder> Bilder { get; set; }
public DbSet<Prüfungen> Prüfungen { get; set; }
public DbSet<Ergebnis> Result { get; set; }
public DbSet<Typen> Typen { get; set; }
public DbSet<Typen_Pruefungen_Bilder> Typen_Pruefungen_Bilder { get; set; }
public DbSet<Einstellungen_KoordinatenSys> Einstellungen_KoordinatenSys { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Einstellungen_KoordinatenSys>()
.HasKey(c => new { c.ID, c.BildID });
modelBuilder.Entity<Ergebnis>()
.HasKey(c => new { c.BildID, c.TypenID, c.PruefungenID, c.BauTeilId });
modelBuilder.Entity<Typen_Pruefungen_Bilder>()
.HasKey(c => new { c.PruefungenID, c.TypenID });
}
}
}
Model
This is the model I need. I speficly need the BauTeilId for the Controller Class.
namespace Qualitätskontrolle.Models
{
public class Ergebnis
{
[Key]
public int TypenID { get; set; }
[Key]
public int PruefungenID { get; set; }
[Key]
public int BildID { get; set; }
[Key]
[StringLength(254)]
public string BauTeilId { get; set; }
public DateTime Date { get; set; } = DateTime.Now;
public string XLabel { get; set; }
public int? X { get; set; }
public string YLabel { get; set; }
public int? Y { get; set; }
public string FehlerCode { get; set; }
public string FehlerName { get; set; }
public string FehlerGruppe1 { get; set; }
public string FehlerGruppe2 { get; set; }
public int Result { get; set; }
//1=IO 2=NIO
}
The result should be a list of BauTeilId which I can then check with the Code from the Controller.
If you need further information I will reply quickly.
I'm assume that it's not asp.net mvc core.
You should create separate class which implement DbContext e.g
public class ApplicationCustomDbContext : DbContext
{
public ApplicationCustomDbContext () : base("name=DefaultConnectionCustom")
{
}
// DbSet for your Entities
}
and in web.config you should specific connection string e.g.
<connectionStrings>
<add name="DefaultConnectionCustom" providerName="System.Data.SqlClient" connectionString="___" />
</connectionStrings>
There are multiple issues.
For ApplicationDbContext in .net core, you should register like below in Startup.cs
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
context.Configuration.GetConnectionString("ApplicationDbContextConnection")));
For connectionstring, you could configure in appsettings.json like
{
"ConnectionStrings": {
"ApplicationDbContextConnection": "Server=(localdb)\\mssqllocaldb;Database=CoreMVC2_2;Trusted_Connection=True;MultipleActiveResultSets=true"
}
}
For use, you could resolve from constructure like
public class HomeController : Controller
{
private readonly ApplicationDbContext _context;
public HomeController(ApplicationDbContext context)
{
_mapper = mapper;
_context = context;
_userManager = userManager;
_userStore = userStore;
}
public async Task<IActionResult> Index()
{
var existingStudent = _context.Result.ToList();
return View();
}
}
I have two separate VS Solutions both work fine accessing the databases associated with them.
How ever I need to look up some details from the other database to be displayed in the other solution.
Ive added the second connection string to the web.config and then added the context to my DAL:
namespace RACentral.DAL
{
public class RACentralContext : DbContext
{
public RACentralContext()
: base("RACDev")
{
}
public DbSet<RiskAssessment> RiskAssessments { get; set; }
public DbSet<Hazard> Hazards { get; set; }
public DbSet<PPE> PPEs { get; set; }
public DbSet<RiskAssessmentPPE> RiskAssessmentPPEs { get; set; }
public DbSet<PeopleExposed> PeopleExposeds { get; set; }
public DbSet<RiskAssessmentPeopleExposed> RiskAssessmentPeopleExposeds { get; set; }
public DbSet<RiskAssessmentHazard> RiskAssessmentHazards { get; set; }
public DbSet<ControlMeasure> ControlMeasures { get; set; }
public DbSet<Severity> Severitys { get; set; }
public DbSet<Likelihood> Likelihoods { get; set; }
public DbSet<AddControlMeasure> AddControlMeasures { get; set; }
public DbSet<Type> Types { get; set; }
public DbSet<SubType> SubTypes { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
public class PeopleContext : DbContext
{
public PeopleContext()
: base("PeopleContext")
{
}
public DbSet<Person> People { get; set; }
}
}
I get an error in the controller
'Not set to an instance of an object,'
Am trying to access it in my controller as follow:
public class RiskAssessmentController : Controller
{
private RACentralContext db = new RACentralContext();
private PeopleContext Peopledb = new PeopleContext();
public ViewResult StartRA()
{
var user = User.Identity.Name;
string userName = user.Substring(7);
var test = Peopled.Person.FirstOrDefault(x => x.PersonId == 1) //Error here
StartRiskAssessmentViewModel viewModel = new StartRiskAssessmentViewModel
{
RiskAssessment = new RiskAssessment(),
Assessor = userName,
};
return View(viewModel);
}
}