将实体映射更改为另一个“未知”表在运行时 [英] Change entity map to another "unknown" table at runtime

查看:99
本文介绍了将实体映射更改为另一个“未知”表在运行时的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我必须编写一个C#应用程序,该应用程序与由旧应用程序创建和备份的SQL Server数据库配合使用。应用程序每年创建新的表,year属性位于表名中。它创建的表的数量可能会根据用户在应用程序中创建的部分数量而有所不同。所以,我必须使用像Cwx_DRyz(相当自我解释...)的表,其中wx可以是这个部分,yz将是一年。一组表的例子可以是:



C01_DR07



C01_DR08



C01_DR09



C02_DR08



C02_DR09



C03_DR06



C04_DR12



所有这些表都可以表示例如客户端。他们将是来自不同部门和年份的客户,但具有相同结构的客户。我的问题是:我可以有一个客户端实体来处理所有这些表,并在运行时将映射从一个更改为另一个?标题说未知,因为我不知道运行时之前的表。



我发现最类似的问题是实体框架将多个表映射到一个实体,答案是使用每个混合类型表继承 ,但对我的情况没有用。



PS:EF版本4.3.1和VS2010



编辑:表没有主键...大多数都有被忽略的列具有唯一的值(整数或字符串)。

解决方案

如果您使用代码优先,您可以根据需要创建一个映射。当您创建的映射与数据库匹配时,这也适用于现有数据库。



因此,无论何时创建上下文,都可以构建要映射到的字符串(tablename)



代码优先的一些代码示例以及如何开始:



DbContext:

  public DbSet< YourEntity> YourEntities {get;组; } 
...

//这个数据库创建时被调用,并为你的配置=>可能不需要你的case
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
ConfigurationRegistrar configurationRegistrar = modelBuilder.Configurations;

new GeneralEntitiesConfiguration(configurationRegistrar);
}

GeneralEntitiesConfiguration是一个类im用于处理配置,只不过是一个帮手它看起来像:

  public class GeneralEntitiesConfiguration 
{
public GeneralEntitiesConfiguration(ConfigurationRegistrar configurationRegistrar)
{
configurationRegistrar.Add(new YourEntityConfiguration());
//和每个实体的其他配置,只是分裂一点,并让它更多的阅读和维护
}
}

YourEntityConfiguration是一个类,我拥有此实体的所有配置:

  public class YourEntityConfiguration:EntityTypeConfiguration< YourEntity> 
{
public YourEntityConfiguration()
{
ToTable(WhatEverYouLike); //这里你可以做任何魔术来将这个实体映射到一个表,只需确保你的属性被映射到正确的colums
Property(entity => entity.Id).HasColumnName(YouColumnName);

//在这里你还要做其他配置
}
}

在应用程序启动时(或首次初始化上下文之前),您必须初始化数据库。因此,您可以使用初始化程序来检查数据库并处理差异。内置的内容有DropCreateDatabaseAlways或DropCreateDatabaseIfModelChanges=>,您将需要创建自己的,只是忽略任何差异。在我的示例中,我创建一个只是在模型不同时抛出异常(我想用第一次尝试用scipt来处理模型更改):

 code> //在使用上下文之前我第一次调用,可以忽略连接字符串
DbContextInitializer.Init(conString);

public static class DbContextInitializer
{
public static void Init(string connectionString)
{
Database.SetInitializer(new CreateDbThrowExceptionIfModelDiffersInitializer< SMDbContext>()) ;

使用(var dbContenxt = new MyDbContext(connectionString))
{
try
{
dbContenxt.Database.Initialize(true);
}
catch(DatabaseModelDiffersException diffException)
{
//一些魔术...
}
catch(Exception ex)
{
// TODO:log
throw;
}
}
}

public class CreateDbThrowExceptionIfModelDiffersInitializer< TContext> :IDatabaseInitializer< TContext>其中TContext:DbContext
{
public void InitializeDatabase(TContext context)
{
using(new TransactionScope(TransactionScopeOption.Suppress))
{
if( !context.Database.Exists())
context.Database.Create();
}

如果(!context.Database.CompatibleWithModel(true))
{
抛出新的DatabaseModelDiffersException(数据库模型不同!
}
}

protected virtual void Seed(TContext context)
{
//如果您喜欢
}创建数据
}

//只是一个异常我用于以后使用
public class DatabaseModelDiffersException:Exception
{
public DatabaseModelDiffersException(string msg):base(msg) )
{}
}
}

希望你有您可以通过实体框架处理动态表名的想法!
如果还有更多问题,请问;)


I have to write a C# application that works with a SQL server database created and mantained by an old application. The application creates new tables each year and the "year property" is in the table name. The number of tables it creates may vary depending of the number of "sections" that the user has created inside the application. So, I have to work with tables like Cwx_DRyz (quite self explanatory...), where "wx" can be the section, and "yz" would be the year. An example of group of table could be:

C01_DR07

C01_DR08

C01_DR09

C02_DR08

C02_DR09

C03_DR06

C04_DR12

And all of those tables could represent, for example, clients. They would be clients from different sections and years, but clients with the same structure.

My question is: Can I have a Client entity to handle all those tables and change the mapping from one to another at runtime? The title says "unknown" because I don't know the tables before runtime.

The most similar question I have found is Entity Framework map multiple tables to one entity and the answer is to use the "Table Per Concrete Type Inheritance", but it is not useful for my case.

PS: EF version 4.3.1 and VS2010

EDIT: The tables don't have primary keys... Most of them have columns that are supossed to have unique values (integer or string).

解决方案

If you use "code first" you could create a mapping as you want. This also works with existing databases when the mapping you have created match the database.

So whenever you create a context you can build the string (tablename) you want to map to.

Some codesamples for "code first" and how you could start:

The DbContext:

public DbSet<YourEntity> YourEntities { get; set; }
...

// this is called when the db gets created and does the configuration for you => maybe not needed in your case
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    ConfigurationRegistrar configurationRegistrar = modelBuilder.Configurations;

    new GeneralEntitiesConfiguration(configurationRegistrar);
}

GeneralEntitiesConfiguration is a class im using to handle the configurations, nothing more than a helper which looks like:

public class GeneralEntitiesConfiguration
{
    public GeneralEntitiesConfiguration(ConfigurationRegistrar configurationRegistrar)
    {
        configurationRegistrar.Add(new YourEntityConfiguration());
        //and additional configurations for each entity, just to splitt it a bit and have it more read and maintenance able
    }
}

YourEntityConfiguration is a class where i have all the configurations for this entity:

public class YourEntityConfiguration : EntityTypeConfiguration<YourEntity>
{
    public YourEntityConfiguration ()
    {
        ToTable("WhatEverYouLike"); // here you can do any magic to map this entity to a table, just make sure that your properties are mapped to the correct colums
        Property(entity => entity.Id).HasColumnName("YouColumnName");

        //and here you also have to do the other configurations
    }
}

At the application startup (or before you initialize your context the first time) you have to initialize the database. Therefore you can use an initializer which checks the database and handles differences. Build in there are things like "DropCreateDatabaseAlways" or "DropCreateDatabaseIfModelChanges" => you would need to create your own which just ignores any differences. In my sample i have create one which just throws an exception when the model differs (i wanted to handle model changes with scipts for the first try):

//before using the context the first time i'm calling, you can ignore the connection string
DbContextInitializer.Init(conString);

public static class DbContextInitializer
{
    public static void Init (string connectionString)
    {
        Database.SetInitializer(new CreateDbThrowExceptionIfModelDiffersInitializer<SMDbContext>());

        using(var dbContenxt = new MyDbContext(connectionString))
        {
            try
            {
                dbContenxt.Database.Initialize(true);
            }
            catch(DatabaseModelDiffersException diffException)
            {
                // some magic...
            }
            catch(Exception ex)
            {
                // TODO: log
                throw;
            }
        }
    }

    public class CreateDbThrowExceptionIfModelDiffersInitializer<TContext> : IDatabaseInitializer<TContext> where TContext : DbContext
    {
        public void InitializeDatabase(TContext context)
        {
            using (new TransactionScope(TransactionScopeOption.Suppress))
            {
                if (!context.Database.Exists())
                    context.Database.Create();
            }

            if (!context.Database.CompatibleWithModel(true))
            {
                throw new DatabaseModelDiffersException("Database Model differs!");
            }
        }

        protected virtual void Seed(TContext context)
        {
            // create data if you like
        }
    }

    // just an exception i'm using for later useage
    public class DatabaseModelDiffersException : Exception
    {
        public DatabaseModelDiffersException(string msg) : base(msg)
        {}
    }
}

Hope you have got an idea of you can handle dynamic table names with entity framework! If there are more questions just ask ;)

这篇关于将实体映射更改为另一个“未知”表在运行时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆