user2023116 user2023116 - 2 months ago 19
ASP.NET (C#) Question

BaseDbContext with shared entities

I have a situation that I thought would be fairly straightforward, but is proving to be difficult.

I have a single database which currently has two different web applications using it. Each application has tables that are used specifically for that application only, while there are also several tables that are shared, such as the ApplicationUser table.

What I am trying to do is have a basecontext that will have all of the shared entities, and have application specific contexts that derive from the basecontext. For the application contexts, many of the shared entities will then have a derived application specific entity that has additional navigation properties.

I'll try to illustrate for clarity:

BaseContext in the shared library

public class BaseContext : DbContext
{
public DbSet<ApplicationUser> ApplicationUsers { get; set; }
}


App1Context in App1

public class App1Context : BaseContext
{
public new DbSet<App1User> ApplicationUsers { get; set; }
}

public class App1User: ApplicationUser
{
//Navigation property specific to App1
public virtual ICollection<SomeApp1Entity> SomeApp1Entity_Creator { get; set; }
}


App2Context in App2

public class App2Context : BaseContext
{
public new DbSet<App2User> ApplicationUsers { get; set; }
}

public class App2User: ApplicationUser
{
//Navigation property specific to App2
public virtual ICollection<SomeApp2Entity> SomeApp2Entity_Creator { get; set; }
}


BaseContext has a dbset for ApplicationUser.

App1Context has a dbset for App1User which is derived from ApplicationUser.

App2Context has a dbset for App2User which also derives from ApplicationUser.

I need the app specific user entities, because App1User may have a navigation property to an entity that is not shared, and applies only to App1. Same goes for App2User.

The main reason I want the BaseContext, is so that I can have a SharedService, that uses this context and has all of my ApplicationUser methods for CRUD.

I have tried several variations, so I can give more information if necessary, I just don't want to make this question too long trying to explain everything I've tried.

I do know that I want the dbset for the BaseContext, so that I can have a shared service. When building the model in the App1Context, I have tried ignoring the ApplicationUser, since I would think that the App1User would be used instead, but this does not work. When I do this, It says there is no key set (Because it is ignoring the base class which has the key, and not picking it up in the derived class). When I don't ignore, I get an error about a discriminator column.

My first question is, am I completely wasting my time with this approach? Is it even possible with Entity Framework 6.3?

If it is possible, how might I go about it differently to find a solution?

Also, let me add that I am using code first, but not worried about migrations. The database exists already, and all changes to the database are made there, then implemented accordingly in the C# code.

Answer

I'm not sure whether this is what you are looking for:

I kept my shared context and entities in a separate library - SharedDbContext namespace:

namespace SharedDataContext
{
    public class BaseDbContext : DbContext
    {
        public BaseDbContext() : base("CFConnection")
        { }

        public DbSet<ApplicationUser> ApplicationUsers { get; set; }

    }

    public partial class ApplicationUser
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
}

And created two application - WebApplication1 and WebApplication2:

WebApplication1 - App1Context - Has its own entity Country with foreign key relation to shared ApplicationUser

namespace WebApplication1
{
    public class App1Context : BaseDbContext
    {
        public DbSet<Country> Countries { get; set; }
    }

    public class Country
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int ApplicationUserId { get; set; }
        public ApplicationUser ApplicationUser { get; set; }
    }
}

WebApplication1 - App2Context - Has its own entity City with foreign key relation to shared ApplicationUser

namespace WebApplication2
{
    public class App2Context : BaseDbContext
    {
        public DbSet<City> Cities { get; set; }
    }

    public class City
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int ApplicationUserId { get; set; }
        public ApplicationUser ApplicationUser { get; set; }
    }

}

Sample controller and result from WebApplication2:

namespace WebApplication2.Controllers
{
    public class CityController : ApiController
    {
        public IEnumerable<City> Get()
        {
            IEnumerable<City> cities;
            using (var context = new App2Context())
            {
                cities = context.Cities.Include(c => c.ApplicationUser).ToList();
            }
            return cities;
        }
    }
}

Result with shared entity details:

enter image description here

I would suggest not to keep context related navigations in the shared entities, rather query it from the other end - If you need to fetch the Cities of "User1", query the DbSet<City> Cities for ApplicationUserId == 1 (this would have been easy if we had ICollection<City> inside ApplicationUser which I'm not sure how to achieve in this case)

Comments