I have tried to make an MVC news system. I started by the use a pluralsight tutorial which was used to create a department with employees. I changed the idea to fit my own purposes, changing the departments to "category" and employees to "newspost". This all works out fine, but now I want to remove the categories, since I don't need categories for my news system. But I can't add to the database using entityframework when I do this.
I have an interface for the datasource that looks like this:
INewMvcSiteDataSource
public interface INewMvcSiteDataSource
{
IQueryable<NewsPost> NewsPosts { get; }
void Save();
}
This is inherited by my DB Context class:
NewMvcSiteDb
public class NewsMvcSiteDb : DbContext, INewMvcSiteDataSource
{
public NewsMvcSiteDb() : base("DefaultConnection")
{
}
public DbSet<NewsPost> NewsPosts { get; set; }
IQueryable<NewsPost> INewMvcSiteDataSource.NewsPosts
{
get { return NewsPosts; }
}
public void Save()
{
SaveChanges();
}
}
I then want to use it in the controller to add a newspost to the database:
NewsController
var newsPost = new NewsPost()
{
Subject = newsModel.Subject,
Content = newsModel.Content,
ImagePath = newsModel.ImagePath
};
_db.NewsPosts.Add(newsPost);
_db.Save();
But this is where the ADD fails with the message: 'System.Linq.IQueryable' does not contain a definition for 'Add' and no extension method 'Add' accepting a first argument of type 'System.Linq.IQueryable' could be found (are you missing a using directive or an assembly reference?)
Now as the error says, its caused by using IQueryable, but I have no idea how else to do it.
Can you guys help?
Thanks.
If you don't mind exposing DbSet via your interface (some people don't like the ORM bleeding into the application),you should be able to do the following:
public interface INewMvcSiteDataSource
{
DbSet<NewsPost> NewsPosts { get; }
void Save();
}
public class NewsMvcSiteDb : DbContext, INewMvcSiteDataSource
{
public NewsMvcSiteDb() : base("DefaultConnection")
{
}
public DbSet<NewsPost> NewsPosts { get; set; }
public void Save()
{
SaveChanges();
}
}
Related
I have an entity called "Role" in my asp.net core 6 Web API application. Below is the DTO of the "Role" entity
public class CreateUpdateRoleDto
{
public Guid Id { get; set; }
.....
}
and I have implemented the Command like mentioned below
public class CreateRoleCommand : CreateUpdateRoleDto, IRequest<Guid>
{
}
with the corresponding Validator
public class CreateRoleCommandValidator : AbstractValidator<CreateRoleCommand>
{
}
Now, I want to implement the batch processing for the same "Role" entity and I have implemented the Command like mentioned below
public class CreateRoleBatchCommand : CreateUpdateRoleDto, IRequest
{
}
with its validator
public class CreateRoleBatchCommandValidator : AbstractValidator<CreateRoleBatchCommand>
{
}
CreateRoleBatchCommandValidator is just a copy of the CreateRoleCommandValidator except that it implements IRequest instead of IRequest but I don't think we need this additional validator as this is just a duplicate code.
Below is the implementation of BatchCommand
public class BatchCommand : IRequest
{
public IEnumerable<IRequest> Requests { get; set; }
}
The batch command validator uses the PolymorphicValidator and sets CreateRoleBatchCommandValidator as a validator for CreateRoleBatchCommand.
public class BatchCommandValidator : AbstractValidator<BatchCommand>
{
public BatchCommandValidator()
{
this.RuleForEach(x => x.Requests).SetAsyncValidator(new PolymorphicValidator<BatchCommand, IRequest>()
.Add<CreateRoleBatchCommand>(new CreateRoleBatchCommandValidator()));
}
}
However, I want to set CreateRoleCommand as a validator for CreateRoleBatchCommand, something like this
public class BatchCommandValidator : AbstractValidator<BatchCommand>
{
public BatchCommandValidator()
{
this.RuleForEach(x => x.Requests).SetAsyncValidator(new PolymorphicValidator<BatchCommand, IRequest>()
.Add<CreateRoleBatchCommand>(new CreateRoleCommandValidator()));
}
}
However it throws the following error.
CS1503 Argument 1: cannot convert from 'CreateRoleCommandValidator' to
'FluentValidation.IValidator'
I'm working on a new project that uses CosmosDB and Entity Framework Core (via the Microsoft.EntityFrameworkCore.Cosmos NuGet package, version 5.0.7; the project itself is .NET Core 5). I'm new to both, and running into an issue I can't sort out.
In short, I need to save a complex object to the database. It's a big model that will have multiple collections of classes underneath it, each with their own properties and some with collections underneath them as well. I'm trying to configure EF with OwnsOne and OwnsMany to store these child objects underneath the top-level one. The code compiles, and will save to the database so long as all the owned objects are left empty. But whenever I put anything into an owned object, either with OwnsOne or OwnsMany, I get a pair of NullReferenceExceptions.
I've tried to strip my code down to the very basics. Here's how it currently looks.
Owner and owned classes:
public class Questionnaire
{
// Constructors
private Questionnaire() { }
public Questionnaire(Guid id)
{
Test = "Test property.";
TV = new TestQ();
Id = id;
}
public Guid Id { get; set; }
public string Test { get; set; }
public TestQ TV { get; set; }
// Public Methods
public void AddForm(Form f)
{
// not currently using this method
//Forms.Add(f);
}
}
public class TestQ
{
public TestQ()
{
TestValue = "test ownsone value";
}
public string TestValue { get; set; }
}
DbContext:
public class QuestionnaireDbContext : DbContext
{
public DbSet<Questionnaire> Questionnaires { get; set; }
public QuestionnaireDbContext(DbContextOptions<QuestionnaireDbContext> options) : base(options) { }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasDefaultContainer(nameof(Questionnaires));
modelBuilder.Entity<Questionnaire>().HasKey(q => q.Id);
modelBuilder.Entity<Questionnaire>().OwnsOne(q => q.TV);
}
}
And the code from the service that calls the dbContext (note that this is based on a generic service that I didn't set up originally). The actual exceptions are thrown here.
public virtual TEntity Add(TEntity entity)
{
_context.Entry(entity).State = EntityState.Added;
_context.SaveChanges();
return entity;
}
Ultimately I need this to work with OwnsMany and a collection, but I figured it might be simpler to get it working with OwnsOne first. The key thing to note here is that if I comment out the line
TV = new TestQ();
in the Questionnaire class, the model persists correctly into CosmosDB. It's only when I actually instantiate an owned entity that I get the NullReferenceExceptions.
Any advice would be much appreciated! Thank you!
Well, I'm not sure why this is the case, but the issue turned out to be with how we were adding the document. Using this generic code:
public virtual async Task<TEntity> Add(TEntity entity)
{
_context.Entry(entity).State = EntityState.Added;
await _context.SaveChanges();
return entity;
}
was the issue. It works just fine if I use the actual QuestionnaireDbContext class like so:
context.Add(questionnaire);
await context.SaveChangesAsync();
I'm using EntityFramework.Patterns in my application and I need to implement soft deletion. Is it possible to implement it using ArchivableRepository ?
If yes can you describe how ?
I did a soft delete by adding an interface to the entity's that support soft deletion.
public interface ISoftDelete
{
DateTime? DeletedDate {get;set;}
}
public class Foo : ISoftDelete
{
public int Id { get;set; }
public DateTime? DeletedDate { get;set; }
}
Then in your Repository, add something like this
public void SoftDelete<T>(T entity) where T : class, IEntity
{
entity.DeletedDate = DateTime.UtcNow;
}
Usage is like this
var entity = repo.GetOne();
repo.SoftDelete(entity);
repo.SaveChanges();
I am learning ServiceStack and developing simple demo for helloworld, but could not find namespace for ISservice interface, my code as per below:
public class Hello
{
public string name { get; set; }
}
public class HelloResponse
{
public string Result { get; set; }
}
public class HelloService : **IService**<Hello>
{
public object Execute(Hello request)
{
return new HelloResponse { Result = "Hello" + request.name };
}
}
public class HelloAppHost : AppHostBase
{
public HelloAppHost() : base("Hello Web Services", typeof(HelloService).Assembly) { }
public override void Configure(Funq.Container container)
{
Routes.Add<Hello>("/hello")
.Add<Hello>("/hello/{Name}");
}
}
Can anyone please tell me what namespace or DLL I need to add for IService interface?
ServiceStack's IService<T> is in the ServiceStack.ServiceHost namespace which lives in the ServiceStack.Interfaces.dll, why here's the class:
https://github.com/ServiceStack/ServiceStack/blob/master/src/ServiceStack.Interfaces/ServiceHost/IService.cs
Note: If you're just starting out, it's probably better to inherit from ServiceStack.ServiceInterface.ServiceBase<T> and override the Run() method which is a useful base class that provides things like auto exception handling for you.
If you want to be able run different code for different HTTP Verbs e.g GET/POST/PUT/DELETE (i.e. creating REST web services) than you want to inherit from RestServiceBase instead and override its OnGet/OnPost/OnPut/OnDelete methods.
I am going though the Apress ASP.NET MVC 3 book and trying to ensure I create Unit Tests for everything possible but after spending a good part of a day trying to work out why edit's wouldn't save (see this SO question) I wanted to create a unit test for this.
I have worked out that I need to create a unit test for the following class:
public class EFProductRepository : IProductRepository {
private EFDbContext context = new EFDbContext();
public IQueryable<Product> Products {
get { return context.Products; }
}
public void SaveProduct(Product product) {
if (product.ProductID == 0) {
context.Products.Add(product);
}
context.SaveChanges();
}
public void DeleteProduct(Product product) {
context.Products.Remove(product);
context.SaveChanges();
}
}
public class EFDbContext : DbContext {
public DbSet<Product> Products { get; set; }
}
I am using Ninject.MVC3 and Moq and have created several unit tests before (while working though the previously mentioned book) so am slowly getting my head around it. I have already (hopefully correctly) created a constructor method to enable me to pass in _context:
public class EFProductRepository : IProductRepository {
private EFDbContext _context;
// constructor
public EFProductRepository(EFDbContext context) {
_context = context;
}
public IQueryable<Product> Products {
get { return _context.Products; }
}
public void SaveProduct(Product product) {
if (product.ProductID == 0) {
_context.Products.Add(product);
} else {
_context.Entry(product).State = EntityState.Modified;
}
_context.SaveChanges();
}
public void DeleteProduct(Product product) {
_context.Products.Remove(product);
_context.SaveChanges();
}
}
BUT this is where I start to have trouble... I believe I need to create an Interface for EFDbContext (see below) so I can replace it with a mock repo for the tests BUT it is built on the class DbContext:
public class EFDbContext : DbContext {
public DbSet<Product> Products { get; set; }
}
from System.Data.Entity and I can't for the life of me work out how to create an interface for it... If I create the following interface I get errors due to lack of the method .SaveChanges() which is from the DbContext class and I can't build the interface using "DbContext" like the `EFDbContext is as it's a class not an interface...
using System;
using System.Data.Entity;
using SportsStore.Domain.Entities;
namespace SportsStore.Domain.Concrete {
interface IEFDbContext {
DbSet<Product> Products { get; set; }
}
}
The original Source can be got from the "Source Code/Downloads" on this page encase I have missed something in the above code fragments (or just ask and I will add it).
I have hit the limit of what I understand and no mater what I search for or read I can't seem to work out how I get past this. Please help!
The problem here is that you have not abstracted enough. The point of abstractions/interfaces is to define a contract that exposes behavior in a technology-agnostic way.
In other words, it is a good first step that you created an interface for the EFDbContext, but that interface is still tied to the concrete implementation - DbSet (DbSet).
The quick fix for this is to expose this property as IDbSet instead of DbSet. Ideally you expose something even more abstract like IQueryable (though this doesn't give you the Add() methods, etc.). The more abstract, the easier it is to mock.
Then, you're left with fulfilling the rest of the "contract" that you rely on - namely the SaveChanges() method.
Your updated code would look like this:
public class EFProductRepository : IProductRepository {
private IEFDbContext context;
public EFProductRepository(IEFDbContext context) {
this.context = context;
}
...
}
public interface IEFDbContext {
IDbSet<Product> Products { get; set; }
void SaveChanges();
}
BUT... the main question you have to ask is: what are you trying to test (conversely, what are you trying to mock out/avoid testing)? In other words: are you trying to validate how your application works when something is saved, or are you testing the actual saving.
If you're just testing how your application works and don't care about actually saving to the database, I'd consider mocking at a higher level - the IProductRepository. Then you're not hitting the database at all.
If you want to make sure that your objects actually get persisted to the database, then you should be hitting the DbContext and don't want to mock that part after all.
Personally, I consider both of those scenarios to be different - and equally important - and I write separate tests for each of them: one to test that my application does what it's supposed to do, and another to test that the database interaction works.
I guess your current code looks something like this (I put in the interface):
public class EFProductRepository : IProductRepository {
private IEFDbContext _context;
// constructor
public EFProductRepository(IEFDbContext context) {
_context = context;
}
public IQueryable<Product> Products {
get { return _context.Products; }
}
public void SaveProduct(Product product) {
if (product.ProductID == 0) {
_context.Products.Add(product);
} else {
_context.Entry(product).State = EntityState.Modified;
}
**_context.SaveChanges();**
}
public void DeleteProduct(Product product) {
_context.Products.Remove(product);
**_context.SaveChanges();**
}
}
public class EFDbContext : DbContext, IEFDbContext {
public DbSet<Product> Products { get; set; }
}
public interface IEFDbContext {
DbSet<Product> Products { get; set; }
}
The problem is EFProductRepository now expects an object implementing the IEFDbContext interface, but this interface does not define the SaveChanges method used at the lines I put between the asteriskes so the compiler starts complaining.
Defining the SaveChanges method on the IEFDbContext interface solves your problem:
public interface IEFDbContext {
DbSet<Product> Products { get; set; }
void SaveChanges();
}