I need to get data from a table I have created using the entity framework. Right now, the web api project is responsible to generate the table out of test data I've created.
The web api project has a folder called DAL with a BookingsContext class in. Looks like this:
public class BookingsContext : DbContext
{
public BookingsContext() : base("BookingsContext")
{
}
// DbSet to bookings
public DbSet<Booking> Bookings { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
If I create an instant of this class in the controller, I can call the DbSet method to get the bookings from the database.
The problem is that I have created a class library called GetBookings. Its is responsible to get all the bookings from the database.
The class which should get the data from the database table is my GetAllBookingsQuery.
// Generic interface
public interface IQuery<out T>
{
T Execute();
}
class GetAllBookingsQuery : IQuery<List<Booking>>
{
// Get a list of bookings from the database.
public List<Booking> Execute()
{
return null;
}
}
Here I can't make a instans of the DbContext and call the simple method public DbSet Bookings { get; set; }
How should I get the data from the table?
You should create separate project with your DAL then add reference to it in both WebApi project and your class library.
Related
I have to build a .net web application accessing tables of an existing db.
The db uses different tables for different companies: customers in company "ACorp" are stored in table "ACorpCustomers", those in company "B" are stored in table "BCorpCustomers".
Using ADO .NET Entity Model, I created a different Db Context for each Company:
public partial class ACorpContext : DbContext
{
public ACorpContext()
: base("name=ACorpContext")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public virtual DbSet<ACorpCustomer> ACorpCustomers { get; set; }
}
}
The edmx generates also the class
public partial class ACorpCustomer
{
public string Name { get; set; }
public string Phone { get; set; }
}
I created a parent class Customer to be used in the application, with the same properties:
public class ACorpCustomer
{
public virtual string Name { get; set; }
public virtual string Phone { get; set; }
}
I havent't found a way to let the specific entity ACorpCustomers inherit from the parent Customer; the edmx returns the inheritance error, but there is no way to override the properties.
Update
In order to avoid edmx file usage, this is what I finally tried out:
I disabled the __MigrationHistory sql table creation using the AutomaticMigrationsEnabled parameter:
internal sealed class Configuration : DbMigrationsConfiguration<MyDomain.Models.ACorpContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
}
}
I disabled the db initialization in the App.config file setting
disableDatabaseInitialization="true"
Then I added a an ADO .NET Entity Model but chose the "code first from database".
In order to be sure not to change the db from the model, I disabled the DB Initializer:
public ACorpContext()
: base("name=ACorpContext")
{
Database.SetInitializer<ACorpContext>(null);
}
Now I expect to be my responsability to be keep in sync the domain model with the db.
Anyway, I feel sure that in case of misalignment no attempt will be done to modify the db.
Without the edmx, I have no more limitations defining inheritance from an abstract class Customer.
I cannot understand why Visual Studio considers this as "Code First" approach, anyway.
Your definition
public partial class ACorpCustomer
has nothing to do with inheritance. partial is a .NET moderator that signifies that your class definition is a part of the bigger definition. For example if you have your class split between 2 code files. .Net "puts" them together and you endup with one type
Here what you seem need to do is
public abstract class Customer
{
public string Name { get; set; }
public string Phone { get; set; }
}
public class ACorpCustomer : Customer
{
// may be, some unique properties here
}
public class BCorpCustomer : Customer
{
// may be, some unique properties here
}
The properties Name and Phone don't even need to be virtual. Looking back into your title, there is nothing that you need to override. Nothing that I see..
This is trivial in Code-First, which you can (and should) use with an existing database. Just map the single Customer entity to the correct table for each DbContext:
public partial class ACorpContext : MyBaseDbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Customer>().ToTable("ACorpContext");
}
public virtual DbSet<Customer> Customers{ get; set; }
}
I am writing an application where I'm using code first design. The models returned from stored procedures do not map directly to an entity from the database.
The issue I am having is while I'm inheriting from an interface on each entity, I'm unable to use these custom models:
System.InvalidOperationException: Cannot create a DbSet for 'CategoryDetailEntity' because this type is not included in the model for the context.
at Microsoft.EntityFrameworkCore.Internal.InternalDbSet1.get_EntityType() at Microsoft.EntityFrameworkCore.Internal.InternalDbSet1.CheckState()
at Microsoft.EntityFrameworkCore.Internal.InternalDbSet1.get_EntityQueryable() at Microsoft.EntityFrameworkCore.Internal.InternalDbSet1.System.Collections.Generic.IAsyncEnumerable.GetAsyncEnumerator(CancellationToken cancellationToken)
at System.Runtime.CompilerServices.ConfiguredCancelableAsyncEnumerable1.GetAsyncEnumerator() at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable1 source, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToArrayAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
Here is the code in my context file:
// Shouldn't be in the database, this is pulled from a stored procedure
public DbSet<Entities.CustomEntities.CategoryDetailEntity> CategoryDetailEntities { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// Exclude models that are not bound to a table
modelBuilder.Entity<Entities.CustomEntities.CategoryDetailEntity>().ToTable(nameof(CategoryDetailEntities), t => t.ExcludeFromMigrations());
}
The entity code:
[NotMapped]
public partial class CategoryDetailEntity : CategoryEntity
{
public int NumProducts { get; set; }
}
CategoryEntity:
[Table("Category")]
public partial class CategoryEntity : BaseEntity
{
public CategoryEntity Parent { get; set; } = null;
public string Icon { get; set; }
}
The base entity has the ID, Created By / Date, Modified By / Date.
Solution:
#JohnM was able to lead me to the solution. I had two issues.
I tried to create a base service class in which my Database models were using. This was the same in my WebAPI, where in the Startup.cs file, I was only using the Base Service to do dependency injection:
services.AddScoped(typeof(IBaseService<>), typeof(BaseService<>));
This meant that the stored procedure was never being called first, only the base class of simple crud functionality.
Once I added all of the services layers explicitly, I was able to call the GetAll function from the correct service as intended.
public CategoryController(ICategoryService service, IMapper mapper) : base(service, mapper) {}
instead of
public CategoryController(IBaseService<CategoryDetailModel> service, IMapper mapper) : base(service, mapper) {}
The accepted Solution solved the other issue, in which using Code First, I wanted to make sure that the model from the Stored Procedure was not included in the migration.
In the Context.cs file:
// Shouldn't be in the database, this is pulled from a stored procedure
public DbSet<CategoryDetailModel> CategoryDetails { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// Exclude models that are not bound to a table
modelBuilder.Entity<CategoryDetailModel>().HasNoKey().ToView(null);
}
Using this, I no longer had to mark the Model as [NotMapped]
public partial class CategoryDetailModel : BaseEntity
{
public string Icon { get; set; }
public int NumProducts { get; set; }
public ImageEntity Image { get; set; }
}
For calling stored procedures I define a regular class to hold the results - so one property for each column in the result set. I then define it as a keyless entity type, so the following goes in the OnModelCreating() method of your database context class:
modelBuilder.Entity<MyModelClass>().HasNoKey().ToView(null);
I am using Entity Framework 6 code-first with an existing database, but having problems mapping my entities to the database tables.
Normally, I would use database-first approach and have my entity and context code generated, but using the designer has become a huge pain.
I have set Database.SetInitializer(null) as I do not want EF to change my schema.
Database schema:
Code-first:
public class Project
{
public int ProjectId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
public class ReleaseControlContext : DbContext
{
public ReleaseControlContext()
: base(ConfigurationManager.ConnectionStrings["ReleaseControl"].ConnectionString)
{
Database.SetInitializer<ReleaseControlContext>(null);
}
public DbSet<Project> Projects { get; set; }
}
Calling code:
using(var context = new ReleaseControlContext())
{
var projects = context.Projects.ToList();
}
The following exception is thrown:
SqlException: Invalid object name 'dbo.Projects'.
This is because my database table is Project and not Projects. I don't want to rename my context's DbSet<Project> to "Project" because that would be semantically incorrect.
Question:
Do I have to use the fluent API/data annotations to map between the Project database table and the DbSet<Project> Projects collection?
You can use the
[Table("Project")]
public class Project {
....
}
annotation against the Project entity, or in the OnModelCreating(DbModelBuilder modelBuilder) you can call modelBuilder.Entity<Project>().ToTable("Project");.
Both would do the same thing.
You should define a class (ie:ProjectMap) that inherits from the generic class EntityTypeConfiguration(T) where T is here your Project class.
In this ProjectMap class, you can define explicitly a table mapping :
this.ToTable("Project", "dbo");
The class ProjectMap should be called in the following method of your DbContext class
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new ProjectMap());
}
Sorry if somebody has already asked this question. I've been looking around but couldn't find anything related.
So, I am using Entity Framework and I am trying to load the list of "Idiomas" from the dataset using the ToList method through the following code:
//List<Idioma> ans = new List<Idioma>(contexto.Idiomas);
return contexto.Idiomas.ToList();
However, the method is returning an empty list, even though I can see through the debugger that the DataSet has elements.
EDIT
I have not put any extra code because there is not any extra code besides those two lines.
I just create a Entity Framework model-first, generated the database, and updated the model from the database to make sure everything was ok.
Contexto is a instance from the class LivroContexto, which implements DbContext (auto generated by vs2012, see below).
LivroContainer:
public partial class LivroContainer : DbContext
{
public LivroContainer() : base("name=LivroContainer")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
}
public DbSet<Idioma> Idiomas { get; set; }
}
Idiomas:
public partial class Idioma
{
public Idioma()
{
this.Traducaos = new HashSet<Traducao>();
}
public int IdIdioma { get; set; }
public string Lingua { get; set; }
public virtual ICollection<Traducao> Traducaos { get; set; }
}
Thank you
nobody can see, why your code is not working, from the amount of code you have posted.
however, make sure following :
the class of the instance contexto inherits DbContext or any child class inheriting DbContext.
make sure, in case, you have not generated the database, through the code,rather mapped an existing database, to a codefirst frontend, that DbSet<Idioma> Idiomas is mapped to proper table. ie.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Idioma>().ToTable("IdiomaTableNameInDatabase");
}
make sure, your connectionString name, that you passed in the DbContext base constructor is present in the web.config, and if you have not passed anything, make sure a connectionString with the name of your DbContext inheriting class is there.
If all these are correct, there is absolutely no reason, why contexto.Idiomas.ToList() won't return anything.
and also, say, your context class is MyContext, then it should be like this:
public class MyContext:DbContext
{
public MyContext:base("ConnectionStringName")
{
}
//--dbSet properties
public DbSet<Idioma> Idiomas{get;set;}
//other overridden methods
}
which you use, on your upper layers like this:
public List<Idioma> GetAllIdiomas()
{
MyContext contexto = new MyContext();
return contexto.Idiomas.ToList();
}
I built a very simple MVC3 application to do a little demo, but I'm running against a problem; I return an entity to my view, edit it and then post it back, but in this process my entity loses it's change-tracking capabilities. When I return the entity to my view it's still an entity framework proxy class, but when it comes back from my view it's a 'Person' class (the entity is called person).
Here's my repository class:
public class PersonRepository : IPersonRepository
{
public EfContext Uow { get; set; }
public PersonRepository(IUnitOfWork uow)
{
Uow = uow as EfContext;
}
// yada yada yada
public void Add(Person person)
{
Uow.Persons.Add(person);
}
}
This entity is sent to my view that has a simple form, created with Html.EditorForModel. After that I post it back to this method:
[HttpPost]
public ActionResult Edit(Person person)
{
if (ModelState.IsValid)
{
_personRepository.Add(person);
_personRepository.Uow.Commit();
return RedirectToAction("Index");
}
return View(person);
}
And tada, it's no longer a tracked proxy class. This results in a primary key violation because entity framework is trying to add my object as a new object, where I just want entity framework to detect the changes and create an update statement instead. Oh by the way, the Commit method in the code above just calls SaveChanges(), here's the class:
public class EfContext : DbContext, IUnitOfWork
{
public DbSet<Account> Accounts { get; set; }
public DbSet<Person> Persons { get; set; }
public void Commit()
{
SaveChanges();
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
By the way, this is my entity class:
public class Person
{
[HiddenInput(DisplayValue = false)]
public Guid Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public virtual ICollection<Account> Accounts { get; set; }
}
Does anyone know how to fix this? I had this working before as far as I can remember, I just don't know how.
Thanks in advance!
I assume that you're creating your repository per request (in the constructor or passed in as a dependency by your IoC framework or something). In that case, the entity that you receive in your controller method is indeed not tracked, because it was created in a different request. You have to "attach" it to the context and mark it as modified so EF knows it has changed and it needs to be saved to the DB
Define an Update method in your repository that will attach the entity and mark it as modified.
public class PersonRepository : IPersonRepository
{
// yada yada yada
public void Add(Person person)
{
Uow.Persons.Add(person);
}
public void Update(Person person)
{
Uow.Persons.Attach(person);
Uow.Entry(person).State = EntityState.Modified;
}
}
[HttpPost]
public ActionResult Edit(Person person)
{
if (ModelState.IsValid)
{
_personRepository.Update(person);
_personRepository.Uow.Commit();
return RedirectToAction("Index");
}
return View(person);
}
There is a 3rd solution here, which I believe is the most failsafe one.
You can configure your MVC action to receive an id integer. Then, using that integer, you retrieve the entity from the database. Then you call the UpdateModel method on the controller. This will bind the new form values to your existing object while it doesn't change the unchanged properties and properties that may not have been in the form.