multiple tables from the same model - c#

I am attempting to use several tables that all follow the same model, this is so that eventually if my application scales farther than needing a single database, the framework has already been laid.
Multiple object sets per type are not supported. The object sets 'Entity' and 'Reddit' can both contain instances of type 'Project.Models.Entity'.
I know this error comes from this section of my dbcontect model:
public DbSet<Entity> Entity {get; set;} //local users
public DbSet<Entity> Reddit { get; set; } //users who registered through reddit
public DbSet<Entity> Twitter { get; set; } //user who registered through twitter
I cant seem to find a way to make this work. I know existing topics cover why this is a problem, but the only solution I seem to find is "well make another database" which while seems simple, still doesn't really explain the issue or how to actually fix it through code.
(using entity framework 6)

This was extracted from the question.
I found the solution and It's so simple I'm rather ashamed that I even had to ask.
just make a new DBcontext for each table
which looks like
RedditDB.cs
public RedditDB() : base("name=Database")
{
}
public DbSet<Entity> Reddit { get; set; }
TwitterDB.cs
public RedditDB() : base("name=Database")
{
}
public DbSet<Entity> Twitter{ get; set; }
and in the controller just put
RedditDB _RDB = new RedditDB();
TwitterDB _TDB = new TwitterDB();

Use inheritance to create a new class with the same properties as the existing Entity.
public class Twitter
{
public int Id { get; set; }
public string Title { get; set; }
public ICollection<EntityC> Lines { get; set; }
}
public class Reddit : Twitter
{
// leave this empty
}
This is better than using separate DB contexts because it is easier to query a single context; you can join tables etc.

Related

Storing functions inside model

Let's assume that I have a class Offer which is:
public class Offer
{
[Key]
public int ID { get; set; }
//...
public virtual List<OfferEventManager> EventManagers { get; set; }
public virtual List<EventDay> EventDays { get; set; }
public virtual List<OfferStatus> OfferStatuses { get; set; }
public virtual List<EstimatedCost> EstimatedCosts { get; set; }
public virtual List<Payment> Payments { get; set; }
}
And I'll have to do some checking, e.g. Someone wants to send an Offer to client, but first Offer has to be in speciffic OfferStatus, some example EventDays and example EstimatedCost. Now let's assume that I'll have to check it not only in one function, but in some more, so I'll need to know what is the latest OfferStatus etc. Should I store a function inside Model e.g. GetLatestStatus() and some other functions or Model should have only properties which are stored in DB? If I can't store functions inside then what is the best way to write some usefull functions which I can use with Offer got from DB call?
You can add method in your model class by partial class public partial class Offer
Can read more at Using partial-classes in Entity Framework with custom properties
What is the best way to write some usefull functions which I can use with Offer got from DB call?
You should follow repository pattern
More reference at https://www.c-sharpcorner.com/article/creating-web-api-with-repository-pattern-and-dependency-injection/
Entity Framework 4 / POCO - Where to start?
Typically, models in EF should be direct models of the database (possibly with some virtual mappings).
I'm not entirely sure what your question is (or what you are wanting), but if all you're wanting is the most recent status, you can do this:
// assume that 'offer' is an Offer from the DB
var latestStatus = offer.OfferStatuses.OrderByDescending(x => x.Timestamp).First();
You can add a "getter" on the model like so:
public class Offer
{
// Getter method
public OfferStatus GetLatestStatus
{
get { return OfferStatuses.OrderByDescending(x => x.Timestamp).FirstOrDefault(); }
set { ; }
}
}

Web Api, Update DB, connection reset 200ok

I have asp.net web api application. I have the table Companies in the databse which have two fields: id and description. Recently I've updated the database and added a new column called CustomerID. After that when I am trying to call getCompanies
private readonly BackendContext _context;
public CompaniesController(BackendContext context)
{
_context = context;
}
// GET: api/Companies
[HttpGet]
public IEnumerable<Company> GetCompanies()
{
return _context.Companies;
}
I get
I think the controller tries to return the old companies model but can't achieve it because it doesnt exist now but I don't know how to fix this though the controller should return the updated model. Maybe I should somehow rebuild the app to make it use the updated version?
Additional code:
Context
public class BackendContext : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityDbContext<IdentityUser>//DbContext
{
public BackendContext(DbContextOptions<BackendContext> options) : base(options) { }
public DbSet<Company> Companies { get; set; }
public DbSet<CompanyToProduct> CompanyToProducts { get; set; }
public DbSet<Product> Products { get; set; }
public DbSet<Customer> Customers { get; set; }
public DbSet<Vendor> Vendors { get; set; }
public DbSet<VendorToProduct> VendorToProducts { get; set; }
public DbSet<Invoice> Invoices { get; set; }
public DbSet<InvoiceItem> InvoiceItems { get; set; }
}
Model
public class Company
{
public int ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public int CustomerID { get; set; }
public virtual Customer Customer { get; set; }
public virtual ICollection<CompanyToProduct> CompaniesToProducts { get; set; }
public virtual ICollection<Invoice> Invoices { get; set; }
}
UPDATE
I've added some values to the table and I got the response of the first company:
[{"id":1,"name":"Google","description":"free food","customerID":6,"customer":null,"companiesToProducts":null,"invoices":null}
BUT I also got the fields which is not specified in the table: customer, companiesToProducts,invoices. Invoices and companiesToProducts are tables in my database and I don't know what is customer referred to. I should also mention that these tables are connected by foreign key.
UPDATE
Error:
Based on the comments on the question above, it sounds like the related tables are all trying to serialize and the overall process is failing likely due to circular references in the object graph. This comment above in particular hints at a solution:
I want to return only the data about companies but the controller also returns another fields like customer, companiesToProducts,invoices
While it's convenient to just return directly from the data context, this has the added side-effect of coupling the API with the database (and with the data access framework, which appears to be the issue here). In API design in general it's always a good idea to explicitly define the "shape" of that API. The fields to return, etc.
Project your result into an explicitly defined shape and return only what you want to return:
var result = _context.Companies
.Select(c => new
{
c.ID,
c.Name,
c.Description,
c.CustomerID
})
.ToList();
This defines specifically what you want to return, fetches only that information from the backing data, materializes it into an in-memory list, and finally then returns it through the API.
There is a potential downside to this, however. Because now we also need to change the return type of your API method. There are a couple options there, such as returning a generic response object or creating a view model which closely approximates your already existing model and starts to feel like duplication.
As with just about anything, it's a balance. Too far in any one direction and that direction starts to become a problem. Personally I often go the route of defining a view model to return:
public class CompanyViewModel
{
public int ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public int CustomerID { get; set; }
}
and returning that:
return _context.Companies
.Select(c => new CompanyViewModel
{
ID = c.ID,
Name = c.Name,
Description = c.Description,
CustomID = c.CustomerID
})
.ToList();
But the reason I normally do this is because I normally work in an environment where the web application is just one application attached to a common shared business domain, so the view models don't feel like code duplication. They're in a separate project, often take a different shape than the backing data objects, etc. But if your domain models are already in your web project and that's the only project you have, there's a strong desire to want to return those.
Another option when that's the case could be to universally set your JSON serialization to ignore circular references:
services.AddMvc()
.AddJsonOptions(
options => options.SerializerSettings.ReferenceLoopHandling
= Newtonsoft.Json.ReferenceLoopHandling.Ignore );
But do keep in mind that this still couples your API to your DB models. Maybe that's okay in this project, but if you ever add a column to your DB that you don't want users to see then it becomes an issue. As with anything, you have options.

Entity Framework Core 2.0 How to automatically Insert Update Delete an detached entity

I have found a lot of threads discussing this topic but none of them have a good solution or I'm just not able to use better search tags :|
I have a Angular2 Frontend with a ASP.Net Core WebApi2 Backend. The database is connected via Entity Framework Core 2.
My issue is just focussed on the backend with EF Core.
My aim is to have a simple method which takes a detached entity (coming from the frontend) which should be updated to the database.
The entity itself has some properties with a lot of navigation properties and these navigation properties have also a lot of navigation properties.
The database model could look like this:
public partial class Project
{
public Project()
{
DocumentNavigation = new HashSet<Document>();
}
public string ProjectNr { get; set; }
public string ProjectTitle { get; set; }
public ICollection<Document> DocumentNavigation { get; set; }
}
public partial class Document
{
public Document()
{
UserNavigation = new HashSet<User>();
}
public int DocumentId { get; set; }
public string DocumentName { get; set; }
public ICollection<User> UserNavigation { get; set; }
}
public partial class User
{
public int UserId { get; set; }
public string UserName { get; set; }
}
My method looks like this:
[HttpPut]
[Route("{projectNr}")]
public IActionResult UpdateProject(string projectNr, [FromBody]Project project)
{
using (abcContext ctx = new abcContext())
{
DoSomething();
ctx.SaveChanges();
}
return NoContent();
}
How do I have to write the method "DoSomething()" in order to deal with this problem?
Imagine, my new object "project" could have new documents, some documents which are still in the database should be deleted because they are no longer in the parameter object "project" and some documents have just changed its normal propoerties like "DocumentName". This could also has happend to the underlaying UserNavigations ...
I just wanted to keep this sample simple. My original entities and the database is much bigger.
To my mind the EF should have a method like "ctx.Update(project)" which manages all these problems???
I cannot believe that I have to do all this stuff manually.
But just in case of doing it manually, how would it look like?
Thanks very much for your support.

How do I delete related objects in Entity framework code first database?

DBContext class is
public class VGDB : DbContext
{
public DbSet<Planet> Planets { get; set; }
}
And model looks like:
public class Planet
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
...
public List<Building> Constructions { get; set; }
}
public class Building
{
[Key]
public int Id { get; set; }
public decimal Lvl { get; set; }
public string Type { get; set; }
}
Repository class:
public class VGDBRepository
{
private readonly VGDB _vgdb;
...
public void RemovePlanets()
{
foreach (Planet planet in _vgdb.Planets)
{
_vgdb.Planets.Remove(planet);
}
_vgdb.SaveChanges();
}
...
}
Entity Framework creates database with two tables: Planets and Buildings, related by Planet_Id field. When I call RemovePlanets() method of my VGDBRepository class it removes planets record from Planets table and sets Planet_Id field of all buildings, related with deleted planets, in Buildings table to null but not deletes them, so I have redundant records in database. I use code-first strategy to create database. How can I force Entity Framework to remove such type of related data???
You would need to cascade your deletes.
Take a look at this:
Stackoverflow Example Cascade Deletes
And this:
Msdn Code First with Enabling Cascade Deletes
I had the exact same problem and I recently figured out how to fix it so I thought I'd just add on to the answer provided by Dima.
The code that you have above for Planet and Building look very similar to how I had my related objects set up; it made sense to me to set up the relations like that. Moreover, the tables seemed to generate correctly with a FK reference back to the parent table. Like you, when I deleted my parent record (Planets, in your case), the child records (Buildings, in your case) still stuck around but the FK field had the parent ID removed so that it just had a null value. The objects were removed from the in memory collection, though, so things were getting out of sync. The thing that was really confusing to me was that Entity Framework Code First is supposed to, by default, cascade deletes like this and I didn't understand why my deletes weren't cascading.
After some digging around, I found that I had to set up a Foreign Key Association within the child class so that Entity Framework did the cascade delete correctly. So you would need to change your code to look like this:
public class Planet
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
...
public List<Building> Constructions { get; set; }
}
public class Building
{
[Key]
public int Id { get; set; }
public decimal Lvl { get; set; }
public string Type { get; set; }
//Add these two properties to create the Foreign Key Association
public int planetID { get; set; }
public Planet planet { get; set; }
}
As soon as I added the two properties and did an automigration on my database, the deletes cascaded just like I expected them to. I'm still a little unclear on why this needs to be done, but that's a subject for a separate post... I just thought that I'd share what had gotten this working for me.
Eager loading may help you. Otherwise, enable lazy loading.
foreach (Planet planet in _vgdb.Planets)
{
_vgdb.Planets.Include(p=>p.Constructions).Remove(planet);
}

Entity Framework 4: Many to Many relationship IQueryable instead of ICollection

Good morning everyone,
I am trying to tackle a problem I run into with EF code first. My schema is the following
public class Article : IUrlNode
{
[Key]
public Guid ArticleID { get; set; }
public string Title { get; set; }
public DateTime DateCreated { get; set; }
public DateTime DateUpdated { get; set; }
public string Summary { get; set; }
[System.ComponentModel.DataAnnotations.InverseProperty("CategoryArticles")]
public virtual IQueryable<Category> ArticleCategories { get; set; }
public string FriendlyUrl
{
get;
set;
}
}
[RouteChild("CategoryArticles")]
public class Category : ContentNode
{
public Guid ServiceId { get; set; }
[System.ComponentModel.DataAnnotations.InverseProperty("ArticleCategories")]
public virtual IQueryable<Article> CategoryArticles { get; set; }
}
I have written code with which I am able to retrieve a category from the database without actually knowing that its a category. From then on I must retrieve a single article of that category again without knowing that its an article. For categories I am relying on the ContentNode base class and for Articles on the IUrlNode interface.
Category retrieval works fine and with a single query but after I actually get the category I have to use reflection to get the navigation property pointed by the RouteChild attribute to find that single article that matches my criteria. Problem is that the navigation property type is ICollection which means that it will at best use lazy loading and will bring all the articles from the database and will find the one I am looking for in memory.
My problem is also described in this previous post (not by me):
Entity Framework Code First IQueryable
Is there a way to have that navigation property as IQueryable or some other design that can go around this limitation?
No there is no way to have navigation property as IQueryable but you can change the collection to IQueryable by using:
IQueryable<Article> query = context.Entry(category).Collection(c => c.articles).Query();
query.Where(...).Load();
Generally your "algorithm" looks pretty strange. You want to work with base class but in the same time you want to access child properties. That sounds wrong and it can most probably be solved in better way (non "generic" way is also better).

Categories

Resources