问题描述:

2015-01-22 The question is solved by myself. I'd like to leave more codes here to show how it works, and wish it can help others.

Like what the guy wants to here(EF code first: inherited dbcontext creates two databases), I'd like to build a DbContext design for reusable class libraries as well.

The design sounds like this:

1. For each class library(dll, project), there is no dbContext, but an interface, to access entities it needs.

2. For each web application(sln, solution), there is only a single DbContext in the web application (and any web apps want to reuse those libs), which inherits all the interfaces.

3. When app started, the web application pass a dbContext instance to all libs via a static interface(might cause some multi-threads prolem? ), so they can access their entities.

4. The web application's dbContext is responsible for db initializing and seeding.

Background: The web application is called "Scrum"(yes, the scrum of agile), there are 2 reusable libraries called Team and Corporation.

Here are some critical codes:

  1. In class libraries called MFCTeam, there is an entity called Team:

    public partial class Team : LeveledItem

    {

    public static IEnumerable<Team> AllTeams(int? corporationId = null)

    {

    return MFCTeamDbFactory.TeamDbContext.Teams.Where(i => i.CorporationId == (corporationId??MFCSite.Corporation.CurrentCorporationId));

    }

    }

    public interface ITeamDbContext

    {

    DbSet<Team> Teams { get; set; }

    }

    public class MFCTeamDbFactory

    {

    public static ITeamDbContext TeamDbContext;

    }

The method "AllTeams" shows an example of accessing db via the interface. There is no direct reference to any DbContext.

Codes in class library Corporation is quite the same so I skipped it.

  1. Then here are codes from the web application Scrum:

    public class ScrumDbContext : DbContext, ITeamDbContext, ICorporationDbContext

    {

    protected override void OnModelCreating(DbModelBuilder modelBuilder)

    {

    Database.SetInitializer(new ScrumDbContextInitializer());

    base.OnModelCreating(modelBuilder);

    modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();

    modelBuilder.Entity<LeveledItem>()

    .Map<Team>(m => m.Requires("Type").HasValue(ItemType.Team))

    .Map<Story>(m => m.Requires("Type").HasValue(ItemType.Story));

    }

    public DbSet<Team> Teams { get; set; }

    public DbSet<Corporation> Corporations {get; set; }

    public DbSet<Story> Stories { get; set; }

So, ScrumDbContext inherits both the interfaces.

DbSetTeams is required by interface ITeamDbContext, and DbSet Corporations is required by interface ICorporaitonDbContext, and DbSetStories is one of ScrumDbContext's own attributes (or required by another library).

  1. In global.cs

     protected void Application_Start()

    {

    //...

    MFCCorporationDbFactory.CorporationDbContext = new ScrumDbContext();

    MFCTeamDbFactory.TeamDbContext = new ScrumDbContext();

    ScrumDbContextInitializer.Seed();

    }

Possible problems:

Accessing entities via a single static dbContext may lead to infliction. If so I will update the codes above.

网友答案:

Sorry, I just found the answer myself. It turned out that in the codes:

        public static IEnumerable<Team> AllTeams(int? corporationId = null)
        {
            return MFCTeamDbFactory.TeamDbContext.Teams.Where(i => i.CorporationId == (corporationId??MFCSite.Corporation.CurrentCorporationId));
        }

MFCSite.Corporation.CurrentCorporationId called another standalone MFCCorporationDbContext and caused that problem. MFCCorporationDbContext is from another reusable class library.

Now I deleted that db context and implemented it with the same design. It works fine now. I updated codes in the question to show how it works, and wish it can be an answer for similar questions.

相关阅读:
Top