Adding WebApi to an existing MVC4 app that uses Entity framework - entity-framework

I've been going around with this for a few days now. I have an existing MVC 4 project that uses entity framework for database creation. The app works as intended but I have a new requirement to add web api to this site. This is a database of quotes and the requirement is to return a simple quote that only contains limited information of the full database entry.
My original model:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
namespace Exercise4.Models
{
public class Quote
{
public int QuoteID { get; set; }
[Required (ErrorMessage = "A Category Field Must be selected or a New one must be Created before continuing")]
public int CategoryID { get; set; }
[Display (Name="Quotation")]
[Required (ErrorMessage = "A Quotation is Required")]
public string QName { get; set; }
[Display (Name= "Author")]
[Required (ErrorMessage = "An Authors Name is Required\n Use 'Unknown' if needed")]
public string QAuthor { get; set; }
[Display (Name = "Category")]
public virtual Category category { get; set; }
[DisplayFormat(DataFormatString = "{0:d}")]
public DateTime Date { get; set; }
public int UserId { get; set; }
}
}
The Simple Quote Model
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
namespace Exercise4.Models
{
public class SimpleQuote
{
public int Id { get; set; }
public string Quote { get; set; }
public string Author { get; set; }
public string Category { get; set; }
}
}
The Context (*Note the SimpleQuote entry was added automagicly when I scaffold the new QuoteApiController)
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Web;
namespace Exercise4.Models
{
public class QuoteContext : DbContext
{
public DbSet<Quote> Quotes { get; set; }
public DbSet<Category> Categories { get; set; }
public DbSet<UserProfile> UserIds { get; set; }
public QuoteContext()
{
Configuration.ProxyCreationEnabled = false;
}
public DbSet<SimpleQuote> SimpleQuotes { get; set; }
}
}
This returns an error when accessing the /api/quoteapi/ page with
The 'ObjectContent`1' type failed to serialize the response body for content type 'application/xml; charset=utf-8'.
Obviously this error occurs because it is trying to return a SimpleQuote Object that doesn't exist in the database.
The API Controller that was created.
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web;
using System.Web.Http;
using Exercise4.Models;
namespace Exercise4.Controllers
{
public class QuoteApiController : ApiController
{
private QuoteContext db = new QuoteContext();
// GET api/QuoteApi
public IEnumerable<SimpleQuote> GetSimpleQuotes()
{
return db.SimpleQuotes.AsEnumerable();
}
// GET api/QuoteApi/5
public SimpleQuote GetSimpleQuote(int id)
{
SimpleQuote simplequote = db.SimpleQuotes.Find(id);
if (simplequote == null)
{
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
}
return simplequote;
}
protected override void Dispose(bool disposing)
{
db.Dispose();
base.Dispose(disposing);
}
}
}
Where am I going awry. I can't return a model that doesn't exist in the database. If I change the call in the api to return a Quote model that works but I only need to return the quote, author and category as strings. Would I just return the Quote object in the controller, pull out the information I need and then return the SimpleQuote object? Not sure how to do that. Any suggestions?

You mentioned scaffolding, are you using Code First to create your Database?
Also you only want the SimpleQuote for returning the information, it looks like its added to your DB context as a table. When what you really want is to pull the data from the Quote Table and build or extract the information you want and return just that. If you don’t have to return a SimpleQuote Object and just return a string you could write something very simplistic like this.
public HttpResponseMessage GetSimpleQuote(int id)
{
var quote = db.Quotes.Find(id);
if (quote == null)
{
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
}
var output += "ID: " + quote.Id + " Quote: " + quote.Quote + " Author: " + quote.Author + " Category: " + quote.Category ;
var response = new HttpResponseMessage();
response.Content = new StringContent(output);
response.Content.Headers.ContentType = new MediaTypeHeaderValue("text/plain");
return response;
}

I 1+ and Accepted #CHammond's response for putting me on the right track. I do need to return a SimpleQuote object. Here is the code I used.
public SimpleQuote GetSimpleQuote(int id)
{
var quote = db.Quotes.Find(id);
if (quote == null)
{
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
}
SimpleQuote output = new SimpleQuote();
output.Quote = quote.QName;
output.Author = quote.QAuthor;
output.Category = db.Categories.Find(quote.CategoryID).CatName;
return output;
}

Related

Entity Framework Core 3 : Type must match overridden member

I have the following two dbcontexts in my Entity Framework Core solution. The OrganisationContext derives from SagitarriContext. I am overiding the base property DbSet<Person> Person. I am getting the following error in the derived class:
Error CS1715
'OrganisationContext.Person': type must be 'DbSet' to match overridden member 'SagitarriContext.Person'
DbContext
namespace Genistar.Data.DbContexts.Interfaces
{
public class SagitarriContext : DbContext, ISagitarriContext
{
public SagitarriContext();
public SagitarriContext(DbContextOptions<SagitarriContext> options);
protected SagitarriContext(DbContextOptions options);
public virtual DbSet<Person> Person { get; set; }
}
}
namespace Genistar.Data.DbContexts
{
public class OrganisationContext : SagitarriContext
{
private readonly ITimeProvider _timeProvider;
private readonly IUserContextResolverFactory _userContextResolver;
public OrganisationContext(DbContextOptions options)
: base(options)
{
}
public OrganisationContext(DbContextOptions options, ITimeProvider timeProvider, IUserContextResolverFactory userContextResolver)
: base(options)
{
_timeProvider = timeProvider;
_userContextResolver = userContextResolver;
}
public override DbSet<Person> Person { get; set; }
}
}
namespace Genistar.Data.DbContexts.Interfaces
{
public interface ISagitarriContext
{
Task<int> SaveChangesAsync(CancellationToken cancellationToken);
DbSet<TQuery> Set<TQuery>() where TQuery : class;
public DatabaseFacade Database { get; }
DbSet<Person> Person { get; set; }
}
}
Usings
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Genistar.Data.DbContexts;
using Genistar.Data.Models;
using Genistar.Organisation.Models.Representative;
using Genistar.Organisation.Models.Unregistered;
using Genistar.Organisation.Models.User;
using Person = Genistar.Organisation.Models.DataModels.Person;
using PersonNote = Genistar.Organisation.Models.DataModels.PersonNote;
using Genistar.Security.Context;
using Genistar.Security.Utility;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
You are not in the same namespace, so the Person class used in DbSet<Person> might be a different one in Genistar.Data.DbContexts.Interfaces and Genistar.Data.DbContexts. Also, we don't see the usings, so there might be an error there.

Swagger-net breaks when using [FromUri] with a complex EF model

I'm using Swagger-Net in my .NET 4.5.1 WebAPI project and one of my API calls is causing the Swagger UI to spin forever on load before coming back with the error below.
Specifically, I found that using [FromUri] in combination with a complex EF entity that has references to other entities ends up causing this.
[HttpPost]
public APIResponse CreateSchool([FromUri]School school)
{
// save school object to db
}
public partial class School : IAuditableEntity,IEntity
{
public School()
{
this.Affiliations = new HashSet<Affiliation>();
this.SchoolAccreditations = new HashSet<SchoolAccreditation>();
this.SchoolAdultRoles = new HashSet<SchoolAdultRole>();
this.SchoolCareOptions = new HashSet<SchoolCareOption>();
this.SchoolDailySessions = new HashSet<SchoolDailySession>();
this.SchoolEligibilityRequirements = new HashSet<SchoolEligibilityRequirement>();
// ...more hashsets
[DataMember]
public int SchoolID { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public bool Active { get; set; }
//...more properties
}
}
Is there a way to still use FromUri and the EF model? Or do I need to change my API call signature?

context.ObjectStateManager, assembly reference is missing in Entity Framework

I cant figure out what assembly refrence am i missing? To evade this error for my upsert logic in entity framework? Might be an old question but unable to find a solution for my project.
- Am following a Code First Approach in EF6.2.0
Please refer the picture i have attached for your reference.
/*Code Attached for reference as well */
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration.Conventions;
using System.Net;
using System.Net.Http;
using System.Configuration;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Host;
namespace ServerlessCoding
{
public static class EF6AddModifyLogic
{
[FunctionName("EF6AddModifyLogic")]
public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Admin, "get", "post", Route = null)]HttpRequestMessage req, TraceWriter log)
{
log.Info("C# HTTP trigger function processed a request.");
// Get request body
dynamic data = await req.Content.ReadAsAsync<object>();
string name = data?.name;
var connectionString = ConfigurationManager.AppSettings["SqlConnection"];
// var connectionString = ConfigurationManager.ConnectionStrings["SqlConnection"].ConnectionString; // Azure Serverless Code
using (var context = new PersonDbContext(connectionString))
{
// If you can't decide existance of the object by its Id you must exectue lookup query:
var person = new Person { Id = 1, Name = "Foo", Age = 32 };
var idVar = person.Id;
if (await context.Persons.AnyAsync(e => e.Id == idVar))
{
context.Persons.Attach(person); // you can now attach your person object to this context
context.ObjectStateManager.ChangeObjectState(person, System.Data.EntityState.Modified);
}
else
{
context.Persons.Add(person);
}
context.SaveChanges();
}
return name == null
? req.CreateResponse(HttpStatusCode.BadRequest, "Please pass a name on the query string or in the request body")
: req.CreateResponse(HttpStatusCode.OK, "Hello " + name);
}
// POCO Class - This should match the SQL table definition.
public class Person
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
// Context Class for creating the tables.
public partial class PersonDbContext : DbContext
{
public PersonDbContext(string cs) : base(cs) { }
public DbSet<Person> Persons { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
}
}

Entity Framework 6.0 - Evaluation of method System.Linq.Queryable.Whewre() requires use of the static field

I am using Entity Framework 6.0 with .NET framework 4.5 inside a SharePoint 2013 project, to get data from a view in a database based on a specific condition.
My Context.cs file looks like this:
namespace Clients
{
using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
public partial class Clients_ReqsEntities : DbContext
{
public Clients_ReqsEntities()
: base("name=Clients_ReqsEntities")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public virtual DbSet<ClientInfo> ClientInfo { get; set; }
}
}
And my ClientInfo.cs file looks like this:
namespace Clients
{
using System;
using System.Collections.Generic;
public partial class ClientInfo
{
public string ClientTitle { get; set; }
public string ClientID { get; set; }
public string ClientUNumber { get; set; }
}
}
I am trying to get data from this view based on the ClientUNumber, using this query:
string anyValue = "something";
var client = (context.ClientInfo.Where(c => c.ClientUNumber.Trim() == anyValue)).FirstOrDefault();
The returned value is always "null", however if I run that line of code in Watch window, I am getting this error:
Evaluation of method System.Linq.Queryable.Where() requires use of the static field System.Data.Entity.Core.Objects.ObjectQuery`1[Clients.ClientInfo].MergeAsMethod, which is not available in this context.
I tried using this query too:
(from c in context.ClientInfo where c.ClientUNumber.Trim() == anyValue select c).FirstOrDefault();
But I am getting the same error.
Some posts suggest to use ToList(), but this will get all records from the DB, and I keep getting Evaluation Timedout. So I don't think this is the right approach. PS: the view has 7k records.
Any help is appreciated.

Error comes as a {"Invalid object name 'dbo.TableName'."}

I'm using Entity Framework and MVC3,
I have used Model First approch...
I have used Company as a Base class and I have inherited the Lead Class from it.
When I run the application its gives an error...
This is Base Class
using System;
using System.Collections.Generic;
namespace CRMEntities
{
public partial class Company
{
public int Id { get; set; }
}
}
This is Lead Class (Child)
using System;
using System.Collections.Generic;
namespace CRMEntities
{
public partial class Lead : Company
{
public Lead()
{
this.Status = 1;
this.IsQualified = false;
}
public Nullable<short> Status { get; set; }
public Nullable<bool> IsQualified { get; set; }
}
}
I have added the controller,and in index view I have added this code...
public class Default1Controller : Controller
{
private CRMWebContainer db = new CRMWebContainer();
//
// GET: /Default1/
public ViewResult Index()
{
return View(db.Companies.OfType<Lead>().ToList());
}
}
This is DB and Model ...
Its giving the inner error -
{"An error occurred while executing the command definition. See the
inner exception for details."} {"Invalid object name
'dbo.Companies'."}
Do you have a Companies table or Company table in your database. It looks like you have a Mapping issue. Entity Framework will make some guesses as to how it pluralizes entity names by default.