簡體   English   中英

實體框架MVC和多個數據庫

[英]Entity Framework MVC and multiple databases

我已經將一個使用存儲庫模式的MVC應用程序與Entity Framework放在一起,並且一切都進行得很順利-但是我遇到了一個障礙,我不確定如何繼續。

我有幾十個具有相同架構的數據庫,我希望能夠在運行時選擇一個或多個數據庫。 例如,假設我從一個用戶數據庫(尚未建立)開始。 該用戶具有與之關聯的連接字符串信息(可能不止一個)。 用戶“登錄”后, 我希望輸入到我的視圖中的Enumerables包含用戶有權訪問的所有數據庫中的匹配數據。

這是我現在擁有的示例:

實體:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations.Schema;

namespace Dashboard.Domain.Entities
{
    public class Flight
    {
        public Guid Id { get; set; }
        public string CarrierCode { get; set; }
        public string FlightNo { get; set; }
        public string MarketingCarrierCode { get; set; }
        public string MarketingFlightNo { get; set; }
        public string Type { get; set; }
        public string TailNo { get; set; }
        public string OriginIATA { get; set; }
        ...

    }
}

數據庫上下文:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data.Entity;
using Dashboard.Domain.Entities;

namespace Dashboard.Domain.Concrete
{
    public class EFDbContext : DbContext
    {
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Passenger>().ToTable("PAX");
        }
        public DbSet<Flight> Flights { get; set; }
        public DbSet<Passenger> PAX { get; set; }
        public DbSet<Airport> Airports { get; set; }
    }
}

飛行庫界面:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Dashboard.Domain.Entities;

namespace Dashboard.Domain.Abstract
{
    public interface IFlightRepository
    {
        IQueryable<Flight> Flights { get; }
    }
}

EF飛行資料庫:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Dashboard.Domain.Abstract;
using Dashboard.Domain.Entities;

namespace Dashboard.Domain.Concrete
{
    public class EFFlightRepository : IFlightRepository
    {
        private EFDbContext context = new EFDbContext();

        public IQueryable<Flight> Flights
        {
            get { return context.Flights; }
        }
    }
}

控制器:

 public class FlightController : Controller
    {
        private IFlightRepository fRepository;
        private IPaxRepository pRepository;
        private IAirportRepository aRepository;
        public int PageSize = 10;

        public FlightController(IFlightRepository flightRepository, IPaxRepository paxRepository, IAirportRepository airportRepository)
        {
            this.fRepository = flightRepository;
            this.pRepository = paxRepository;
            this.aRepository = airportRepository;
        }

        public ViewResult List(byte status = 1, int page = 1)
        { ...

我希望這些存儲庫包含指定的所有連接字符串中的所有數據,但是我不知道從哪里開始。 EF從web.config獲取我的連接字符串,但是我需要能夠以某種方式動態設置它,而且我需要將多個數據庫的數據放入存儲庫中。

這可能嗎? 我應該提到該站點是只讀的,因此我不需要將更改寫回到數據庫中。

更新:

我更改了代碼,以便可以將連接字符串傳遞給EF信息庫的構造函數,但是當我嘗試合並來自兩個不同上下文的IQueryable時,如下所示:

public class EFFlightRepository : IFlightRepository
{
    private EFDbContext context1 = new EFDbContext(connectionstring1);
    private EFDbContext context2 = new EFDbContext(connectionstring2);
    private IQueryable<Flight> context;

    public EFFlightRepository()
    {
        context = (IQueryable<Flight>)context1.Flights.Union(context2.Flights);
    }
    public IQueryable<Flight> Flights
    {
        get { return context;}
    }
}

我得到這個例外:

指定的LINQ表達式包含對與不同上下文關聯的查詢的引用。

如何合並它們,以便像運行一組數據一樣運行LINQ查詢?

很難給出詳細的解決方案,因為它實際上取決於您的軟件設計選擇,但是我認為可能的解決方案包括以下幾方面:

1)一種方法/類,該方法/類使用DbContext構造函數創建DbContext對象的集合,該構造函數具有與Willian Werlang所述的連接字符串或連接字符串名稱(是相同的構造函數):

new DbContext("DB1");

2)您的存儲庫應該能夠接受DbContext的列表,而不是單個列表。 例如,可以將其注入其構造函數。

3)檢索方法應遍歷存儲庫並加載(分離時急於加載)相關對象。

4)可以使用以下代碼將檢索到的對象與其DbContext分離:

dbContext.Entry(entity).State = EntityState.Detached;

這不是必需的,但可能是一個考慮因素,因為您將返回不同數據源的混合。

5)檢索/分離的對象應添加到返回的List <>中,否則您可以使用IEnumerable <>逐個返回的結果作為返回類型。

在這種情況下,無法返回IQueryable,但將結果作為IEnumerable。

飛行庫的簡單檢索方法示例如下:

public IEnumerable<Flight> GetFlights() {
    // dbContexts is an IEnumerable<DbContext> that was injected in the constructor
    foreach (var ctx in dbContexts) {
        foreach (var flight in ctx.Flights) {
            yield return flight;
        }
    }
}

您可以在web.config上設置多個數據庫,但使用不同的名稱,因此DbContext可以接收所需的數據庫名稱作為參數,例如:

new DbContext("DB1");

這樣,您可以選擇從哪個數據庫中獲取數據,但是我認為僅使用onde dbContext不能同時從多個數據庫中獲取數據。

我的解決方案是將我的存儲庫類更改為采用連接字符串參數,如下所示:

namespace Dashboard.Domain.Concrete
{
    public class EFFlightRepository : IFlightRepository
    {
        private EFDbContext context;

        public IQueryable<Flight> Flights
        {
            get { return context.Flights;}
        }

        public EFFlightRepository(string connectionString)
        {
            context = new EFDbContext(connectionString);
        }
    }
}

然后創建一個工廠類(使用Ninject.Extensions.Factory)在創建存儲庫時傳遞參數如何使用Ninject沿依賴關系鏈向下傳遞參數 ):

namespace Dashboard.Domain.Factories
{
    public interface IFlightRepoFactory
    {
        IFlightRepository CreateRepo(string connectionString);
    }
}

我還有另一個Factory類,它基於字符串列表(用於饋送到各個存儲庫類的連接字符串)生成一個存儲庫列表。

namespace Dashboard.Domain.Factories
{
    public interface IRepoCollectionFactory
    {
        IRepositoryCollection CreateCollection(List<string> connectionStrings);
    }
}

然后,在我的控制器類中,遍歷Collection Factory生成的Collection,運行需要在每組存儲庫上運行的任何查詢,然后合並結果。

最終,這給了我一個列表,其中包含每個存儲庫中每個查詢的所有數據。

public FlightController(IRepoCollectionFactory repoCollectionFactory)
{
    this.repoCollectionFactory = repoCollectionFactory;
    this.collection = repoCollectionFactory.CreateCollection(new List<string> { 
                // each connection string for each database here
    });
}

Ninject類中的綁定:

    private void AddBindings()
    {
        ninjectKernel.Bind<IFlightRepoFactory>().ToFactory();
        ninjectKernel.Bind<IAirportRepoFactory>().ToFactory();
        ninjectKernel.Bind<IPaxRepoFactory>().ToFactory();
        ninjectKernel.Bind<IRepoFactory>().ToFactory();
        ninjectKernel.Bind<IRepoCollectionFactory>().ToFactory();

        ninjectKernel.Bind<IRepositories>().To<EFRepositories>();
        ninjectKernel.Bind<IRepositoryCollection>().To<EFRepositoryCollection>();
        ninjectKernel.Bind<IFlightRepository>().To<EFFlightRepository>();
        ninjectKernel.Bind<IPaxRepository>().To<EFPaxRepository>();
        ninjectKernel.Bind<IAirportRepository>().To<EFAirportRepository>();
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM