实体框架中的泛型
本文关键字:泛型 框架 实体 | 更新日期: 2023-09-27 17:57:29
我面临着一个关于实体框架的难题。使用mvc 4和实体框架5.0,我正在开发一个现有应用程序的插件,该应用程序具有以下表名:
dbo.company1_contact
dbo.company1_product
dbo.company2_contact
dbo.company2_product
用户通常只能访问一号公司或二号公司,我想支持所有公司的用户。这就需要一种通用的方法。
因此,我使用相同的实体和上下文名称创建了两个edmx文件,一个用于1号公司,另一个用于2号公司。产生等类别
Entities.Company1.Contact
Entities.Company1.Product
Entities.Company2.Contact
Entities.Company2.Product
和两个上下文类:
Entities.Company1.Company1Entities
Entities.Company2.Company2Entities
这还不足以以通用的方式使用它,因为例如,控制器需要一个存储库变量,例如:
private Company1Entities db = new Company1Entities()
对于2号公司来说,这将是
private Company2Entities db = new Company2Entities()
通用方法是使用接口ICompanyEntities和工厂来获得正确的存储库。但是-上下文类中包含的DbSet属性可能具有相同的名称,它们不属于相同的类型。具体地说,例如,上下文类中设置的产品现在被定义为
DbSet<Entities.Company1.Product> Products {}
与
DbSet<Entities.Company2.Product> Products {}
因此,我修改了T4模板,为每种类型生成一个接口,让每个实体实现该接口,并将每个上下文类生成为包含具有该接口的dbset,例如
public interface IRepository {}
public interface IContact {}
public interface IProduct {}
每家公司:
public class Product : IProduct {}
以及在上下文类中:
public class Company1Entities : DbContext, IRepository
{
...
public DbSet<IProduct> Products { get; set; }
public DbSet<IContact> Contacts { get; set; }
}
这个汇编得很好,我希望这个问题能得到解决。但实体框架在很大程度上阻碍了它,所以我不得不完全回滚。
然后我尝试对db变量使用dynamic关键字,但linq不接受。有人能给我解释一下如何解决这个问题吗?我开始觉得这在实体框架中是不可能的,除非我把我的控制器写成部分,并为每个公司实现一个控制器,只包含声明db变量的行。这是我真的不想做的事情,我宁愿完全复制控制器类。是否有解决方案,通用方法?我是不是遗漏了什么?我们将不胜感激。
因为它们都是完全相同的模型,所以可以对两者使用相同的上下文。只是根据客户的不同加载不同的数据。在构造函数中取一个指示表前缀的值,然后重写OnModelCreating
方法以在表映射上设置该前缀。
public class GenericEntities : DbContext, IRepository
{
//...
private string TablePrefix { get; set; }
public GenericEntities(string tablePrefix)
{
this.TablePrefix = tablePrefix;
}
public DbSet<Product> Products { get; set; }
public DbSet<Contact> Contacts { get; set; }
public override OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Product>.ToTable(TablePrefix + "_product");
modelBuilder.Entity<Customer>.ToTable(TablePrefix + "_customer");
}
}
重要编辑:默认配置将在应用程序中第一次创建GenericEntities时缓存您的模型,并且您永远不会创建两个版本的模型。最简单/最快的方法是为每个客户端创建GenericEntity的子类,以便它们分别缓存。长期使用许多客户端,您需要实现自己的缓存方案(基于表前缀而不是实体类类型)。
public class Customer1Entities : GenericEntities
{
public Customer1Entities() : base("customer1") {}
}
public class Customer2Entities : GenericEntities
{
public Customer2Entities() : base("customer2") {}
}
just.anotherprogrammer的答案是正确的,但不适用于我的情况,因为我首先使用数据库。相反,我现在使用T4来生成通用实体,我为每个实体和公司创建代码,例如
IQueryable<GenericCustomer> Customers
{
get
{
return from c in db.Customers1
select new GenericCustomer()
{ Name = c.Name, ... }
}
}
这解决了我的大部分问题。