Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用单个实体框架Core DbContext管理具有同名表的多个数据库模式_C#_.net Core_Entity Framework Core_Database Schema_Dbcontext - Fatal编程技术网

C# 使用单个实体框架Core DbContext管理具有同名表的多个数据库模式

C# 使用单个实体框架Core DbContext管理具有同名表的多个数据库模式,c#,.net-core,entity-framework-core,database-schema,dbcontext,C#,.net Core,Entity Framework Core,Database Schema,Dbcontext,在.NET Core 2.1库中我需要访问在多个模式中组织的MySQL数据库,这些模式中的表可以具有相同的名称。我无法对DB进行任何更改,因为它来自另一家公司。 对于大多数表,我需要只读访问,并且希望使用单EF CoreDbContext 实际上,我在初始化过程中收到以下错误消息: InvalidOperationException:无法将表“tbl_panel”用于 实体类型“Db2Panels”,因为它正用于实体 键入“Db1Panels”,它们之间没有关系 主键 我认为问题的关键在于配置方

.NET Core 2.1库中我需要访问在多个模式中组织的
MySQL
数据库,这些模式中的表可以具有相同的名称。我无法对DB进行任何更改,因为它来自另一家公司。 对于大多数表,我需要只读访问,并且希望使用单EF Core
DbContext

实际上,我在初始化过程中收到以下错误消息:

InvalidOperationException:无法将表“tbl_panel”用于 实体类型“Db2Panels”,因为它正用于实体 键入“Db1Panels”,它们之间没有关系 主键

我认为问题的关键在于配置方法,它不应该只调用一次,而应该调用N次,对于具有不同模式的实体的每个实例都调用一次(
db\u machine\u 1.tbl\u panel
db\u machine\u 2.tbl\u panel
,等等)。 我怎样才能达到我的目标

这是我的实际实现

数据库模式

// db_machine_1 schema
db_machine_1.tbl_panel
db_machine_1.tbl_basket
db_machine_1.tbl_unit

// db_machine_2 schema
db_machine_2.tbl_panel
db_machine_2.tbl_basket
db_machine_2.tbl_discard

// Other db_machine_X schemas with similar structure...
public class Panel
{
    public long Id { get; set; }
    public string SN { get; set; }
    // Other properties...
}

public class Basket
{
    public long Id { get; set; }
    public string Description { get; set; }
    // Other properties...
}
public class PanelConfiguration : IEntityTypeConfiguration<Panel>
{
    public void Configure(EntityTypeBuilder<Panel> builder)
    {
        builder.ToTable("tbl_panel");

        builder.HasKey(e => e.Id);

        builder.Property(e => e.Id)
            .HasColumnName("ID_Record");

        builder.Property(e => e.SN)
            .HasColumnName("Serial")
            .HasMaxLength(20);

        // Other properties configuration...
    }
}

public class BasketConfiguration : IEntityTypeConfiguration<Basket>
{
    public void Configure(EntityTypeBuilder<Basket> builder)
    {
        builder.ToTable("tbl_basket");

        builder.HasKey(e => e.Id);

        builder.Property(e => e.Id)
            .HasColumnName("ID_Record");

        builder.Property(e => e.Description)
            .HasColumnName("Desc")
            .HasMaxLength(100);

        // Other properties configuration...
    }
}

// Other IEntityTypeConfiguration implementations for other tables...

// This extension method is used to automatically load all Configurations
// of the various entities
public static class ModelBuilderExtensions
{
    public static void ApplyAllConfigurations(this ModelBuilder modelBuilder)
    {
        var applyConfigurationMethodInfo = modelBuilder
            .GetType()
            .GetMethods(BindingFlags.Instance | BindingFlags.Public)
            .First(m => m.Name.Equals("ApplyConfiguration", StringComparison.OrdinalIgnoreCase));

        var ret = typeof(T).Assembly
            .GetTypes()
            .Select(t => (t, i: t.GetInterfaces().FirstOrDefault(i => i.Name.Equals(typeof(IEntityTypeConfiguration<>).Name, StringComparison.Ordinal))))
            .Where(it => it.i != null)
            .Select(it => (et: it.i.GetGenericArguments()[0], cfgObj: Activator.CreateInstance(it.t)))
            .Select(it => applyConfigurationMethodInfo.MakeGenericMethod(it.et).Invoke(modelBuilder, new[] { it.cfgObj }))
            .ToList();
    }
}
DbContext配置

public class MyDbContext : DbContext
{
    // Schema: db_machine_1
    public DbSet<Panel> Db1Panels { get; set; }
    public DbSet<Basket> Db1Baskets { get; set; }
    public DbSet<Unit> Db1Units { get; set; }

    // Schema: db_machine_2
    public DbSet<Panel> Db2Panels { get; set; }
    public DbSet<Basket> Db2Baskets { get; set; }
    public DbSet<Discard> Db2Discards { get; set; }

    // Other schemas DbSet<X> objects...

    // Arrays to access the specific DbSet by using the schema number:
    // Panels[1] -> Db1Panels, Panels[2] -> Db2Panels, ...
    public DbSet<Panel>[] Panels { get; }
    public DbSet<Basket>[] Baskets { get; }
    // Other arrays for other DbSet<X> objects...

    public MyDbContext(DbContextOptions<MyDbContext> options)
        : base(options)
    {
        // Arrays initialization
        List<DbSet<Panel>> dbPanelList = new List<DbSet<Panel>>();
        dbPanelList.Add(Db1Panels);
        dbPanelList.Add(Db2Panels);
        Panels = dbPanelList.ToArray();

        List<DbSet<Basket>> dbBasketList = new List<DbSet<Basket>>();
        dbBasketList.Add(Db1Baskets);
        dbBasketList.Add(Db2Baskets);
        Baskets = dbBasketList.ToArray();

        // Initialization for other DbSet<X> objects...
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.ApplyAllConfigurations<MyDbContext>();
        modelBuilder.ApplyAllConversions();
    }
}
配置

// db_machine_1 schema
db_machine_1.tbl_panel
db_machine_1.tbl_basket
db_machine_1.tbl_unit

// db_machine_2 schema
db_machine_2.tbl_panel
db_machine_2.tbl_basket
db_machine_2.tbl_discard

// Other db_machine_X schemas with similar structure...
public class Panel
{
    public long Id { get; set; }
    public string SN { get; set; }
    // Other properties...
}

public class Basket
{
    public long Id { get; set; }
    public string Description { get; set; }
    // Other properties...
}
public class PanelConfiguration : IEntityTypeConfiguration<Panel>
{
    public void Configure(EntityTypeBuilder<Panel> builder)
    {
        builder.ToTable("tbl_panel");

        builder.HasKey(e => e.Id);

        builder.Property(e => e.Id)
            .HasColumnName("ID_Record");

        builder.Property(e => e.SN)
            .HasColumnName("Serial")
            .HasMaxLength(20);

        // Other properties configuration...
    }
}

public class BasketConfiguration : IEntityTypeConfiguration<Basket>
{
    public void Configure(EntityTypeBuilder<Basket> builder)
    {
        builder.ToTable("tbl_basket");

        builder.HasKey(e => e.Id);

        builder.Property(e => e.Id)
            .HasColumnName("ID_Record");

        builder.Property(e => e.Description)
            .HasColumnName("Desc")
            .HasMaxLength(100);

        // Other properties configuration...
    }
}

// Other IEntityTypeConfiguration implementations for other tables...

// This extension method is used to automatically load all Configurations
// of the various entities
public static class ModelBuilderExtensions
{
    public static void ApplyAllConfigurations(this ModelBuilder modelBuilder)
    {
        var applyConfigurationMethodInfo = modelBuilder
            .GetType()
            .GetMethods(BindingFlags.Instance | BindingFlags.Public)
            .First(m => m.Name.Equals("ApplyConfiguration", StringComparison.OrdinalIgnoreCase));

        var ret = typeof(T).Assembly
            .GetTypes()
            .Select(t => (t, i: t.GetInterfaces().FirstOrDefault(i => i.Name.Equals(typeof(IEntityTypeConfiguration<>).Name, StringComparison.Ordinal))))
            .Where(it => it.i != null)
            .Select(it => (et: it.i.GetGenericArguments()[0], cfgObj: Activator.CreateInstance(it.t)))
            .Select(it => applyConfigurationMethodInfo.MakeGenericMethod(it.et).Invoke(modelBuilder, new[] { it.cfgObj }))
            .ToList();
    }
}

这有可能吗?

我认为,对于不同的表,您无法避免使用两个不同的EF对象,而且您可能不应该这样做,因为它们在将来的某个时候可能会出现分歧

您至少需要两个类
Db1Panel
Db2Panel
。我假设“Db”前缀实际上意味着不同的模式,而不是不同的数据库

然而,这不应该是一个大问题,因为C#内部还有其他方法可以让他们以类似的方式行事。突然想到的两个选项是让它们从同一基类继承,或者让它们实现一个接口:

public abstract class PanelBase
{
    public long Id { get; set; }
    // other properties
}

[Table("tbl_panel", Schema = "Db1")]
public class Db1Panel : PanelBase{}

[Table("tbl_panel", Schema = "Db2")]
public class Db2Panel : PanelBase{}
如果选择实现接口,则需要在每个类中重复属性,但重构工具使这变得非常容易

public interface IPanel
{
    public long Id { get; set; }
}

[Table("tbl_panel", Schema = "Db1")]
public class Db1Panel : IPanel
{
    public long Id { get; set; }
}

[Table("tbl_panel", Schema = "Db2")]
public class Db2Panel : IPanel
{
    public long Id { get; set; }
}

或根据应用程序的大小,您可以考虑拥有域对象的另一个命名空间,并将数据库对象映射到它中:

您应该能够使用<代码>表< /C>属性。有一个参数
Schema
,允许您设置架构名称。有关文档,请参阅。在你的情况下,你会得到

[Table("Table1", Schema="Schema1")]
public class Entity1Schema1
{
    public string Property1 {get;set;}
}

[Table("Table1", Schema="Schema2")]
public class Entity1Schema2
{
    public string Property1 {get;set;}
}

当然,您可以使用接口或基类来重构代码,正如前面提到的@ste fu。

您是指具有多个模式的单个数据库吗?也许这会有所帮助:@KiranJoshi具有多个模式的单个MySQL数据库实例。
db\u machine\u X
前缀是架构名称。我有一个用户可以访问所有这些内容。@Isma问题是一样的。他对不同的模式使用了一个
DbContext
,到目前为止,对我来说一切都还可以。但我也希望避免实体对象重复,而是希望在不同的
DbSet
对象中多次重复使用它们,其中每个对象都应该引用相同的实体,这些实体应该配置为映射不同的模式(以及不同的表)。我相信这是唯一的方法,由于单个实体类不能与多个
DbSet
(表)关联。@ste fu Yes,
db
前缀标识MySQL架构。我想避免实体的重复,因为我的模式很多,其中类似的表也很多…@ste fu我做了一些实验,但正如@IvanStoev所说,没有机会将单个实体与多个
DbSet
属性关联起来…:-(然而,现在我使用了基类抽象类和派生类解决方案,我仍然想知道是否至少可以创建基类的数组(
public DbSet[]Panels{get;}
),其中包括我的所有派生类。请查看更新问题。