在 EF 数据库上下文中两次使用相同的 c# 模型
Use the same c# model twice in an EF database context
我们有一个应用程序,其中一组复杂的数据模型保存在数据存储中 - 我们将单独的数据集称为 DataFiles。可以将这些数据文件调用到编辑器中进行更改,完成后将其保存回商店。这个过程与从硬盘驱动器加载 Excel 文件、编辑然后选择保存或另存为没有什么不同。
我们当前的应用程序设计将数据文件存储和数据文件编辑器分成两个数据库和两个数据库上下文。通过这种方式,我们可以对存储和编辑器使用相同的 C# 模型,并且可以将已编辑的数据文件映射回存储,反之亦然。最简单的情况:
- 得到一个
- A = B
- 保存B
这消除了 1:1 属性映射的需要。对于更复杂的数据结构,它也使得将 A 注入 B 相对容易
我们需要为商店和编辑器移动到单一的数据库上下文。
问题是 - 在单个数据库上下文中,我们可以将一个 C# 数据模型绑定到两个单独的数据 table 数据库吗?
这是一个非常简单的例子,说明了我们正在尝试做的事情。这不起作用,因为 EF 试图将两个 DbSet 定义映射到一个 table(称为 DataFile)
// C# model
namespace MyApp.Models
{
public partial class DataFile
{
public int Id { get; set; }
public int MyDataField { get; set; }
public string MyOtherDataField { get; set; }
}
}
// Database binding
public class AppDbContext : DbContext
{
public AppDbContext() : base("name=AppDbContext"){}
// Store Data File Access
public virtual DbSet<DataFile> StoreDataFiles { get; set; }
// Active Data File Access
public virtual DbSet<DataFile> EditorDataFiles { get; set; }
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
我认为这是一个解决方案,可以满足您的需求,唯一需要注意的是 ID 字段在 table 之间必须是唯一的,并且你需要自己处理。除此之外,此技术源自 here,称为 'Table Per Concrete Type'。
我们要做的是使用您的类型所具有的属性创建一个抽象 class,并从中继承。这应该使两个 classes 保持同步,并且您可以通过来回转换来获得一个或另一个。这里重要的是 DatabaseGeneratedAttribute
设置为 'None';使用此技术,由于两个 tables 将具有相同的 PK,因此 EF 无法判断它需要在 tables 之间共享它们。
父class必须是抽象的;至少,这是我让它识别为 DbSet 但不为其创建 table 的唯一方法。
public abstract class DataFileParent
{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
public int MyDataField { get; set; }
public string MyOtherDataField { get; set; }
}
public class DataFileEditor : DataFileParent
{
}
public class DataFileStore : DataFileParent
{
}
现在我们可以创建 Context
class,只有一个 DbSet
将在 table 之间共享。我们还将告诉上下文我们希望根据实体的具体类型将实体映射到不同的 table,这是在 OnModelCreating
方法中完成的。
public class Context : DbContext
{
public DbSet<DataFileParent> DataFileParents { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<DataFileEditor>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("DataFileEditor");
});
modelBuilder.Entity<DataFileStore>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("DataFileStore");
});
}
}
差不多就这些了!现在,当你想创建一个 DataFileStore
或 DataFileEditor
时,你可以这样做,并像这样添加它:(假设 Store
是一个 DataFileStore
类型的变量)
using (var db = new Context())
{
db.DataFileParents.Add(Store);
db.SaveChanges();
}
我为此制作了一个小控制台应用程序并将其放在 GitHub。
我们有一个应用程序,其中一组复杂的数据模型保存在数据存储中 - 我们将单独的数据集称为 DataFiles。可以将这些数据文件调用到编辑器中进行更改,完成后将其保存回商店。这个过程与从硬盘驱动器加载 Excel 文件、编辑然后选择保存或另存为没有什么不同。
我们当前的应用程序设计将数据文件存储和数据文件编辑器分成两个数据库和两个数据库上下文。通过这种方式,我们可以对存储和编辑器使用相同的 C# 模型,并且可以将已编辑的数据文件映射回存储,反之亦然。最简单的情况:
- 得到一个
- A = B
- 保存B
这消除了 1:1 属性映射的需要。对于更复杂的数据结构,它也使得将 A 注入 B 相对容易
我们需要为商店和编辑器移动到单一的数据库上下文。
问题是 - 在单个数据库上下文中,我们可以将一个 C# 数据模型绑定到两个单独的数据 table 数据库吗?
这是一个非常简单的例子,说明了我们正在尝试做的事情。这不起作用,因为 EF 试图将两个 DbSet 定义映射到一个 table(称为 DataFile)
// C# model
namespace MyApp.Models
{
public partial class DataFile
{
public int Id { get; set; }
public int MyDataField { get; set; }
public string MyOtherDataField { get; set; }
}
}
// Database binding
public class AppDbContext : DbContext
{
public AppDbContext() : base("name=AppDbContext"){}
// Store Data File Access
public virtual DbSet<DataFile> StoreDataFiles { get; set; }
// Active Data File Access
public virtual DbSet<DataFile> EditorDataFiles { get; set; }
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
我认为这是一个解决方案,可以满足您的需求,唯一需要注意的是 ID 字段在 table 之间必须是唯一的,并且你需要自己处理。除此之外,此技术源自 here,称为 'Table Per Concrete Type'。
我们要做的是使用您的类型所具有的属性创建一个抽象 class,并从中继承。这应该使两个 classes 保持同步,并且您可以通过来回转换来获得一个或另一个。这里重要的是 DatabaseGeneratedAttribute
设置为 'None';使用此技术,由于两个 tables 将具有相同的 PK,因此 EF 无法判断它需要在 tables 之间共享它们。
父class必须是抽象的;至少,这是我让它识别为 DbSet 但不为其创建 table 的唯一方法。
public abstract class DataFileParent
{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
public int MyDataField { get; set; }
public string MyOtherDataField { get; set; }
}
public class DataFileEditor : DataFileParent
{
}
public class DataFileStore : DataFileParent
{
}
现在我们可以创建 Context
class,只有一个 DbSet
将在 table 之间共享。我们还将告诉上下文我们希望根据实体的具体类型将实体映射到不同的 table,这是在 OnModelCreating
方法中完成的。
public class Context : DbContext
{
public DbSet<DataFileParent> DataFileParents { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<DataFileEditor>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("DataFileEditor");
});
modelBuilder.Entity<DataFileStore>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("DataFileStore");
});
}
}
差不多就这些了!现在,当你想创建一个 DataFileStore
或 DataFileEditor
时,你可以这样做,并像这样添加它:(假设 Store
是一个 DataFileStore
类型的变量)
using (var db = new Context())
{
db.DataFileParents.Add(Store);
db.SaveChanges();
}
我为此制作了一个小控制台应用程序并将其放在 GitHub。