从EF模型中删除必需属性,因为它是只读的。

11

我有一个小数据模型的项目,以只读方式使用EF模型。

如果非空且没有默认值,我不需要模型中所有的列,但是我必须要有它们。

我该如何避免包括这些无用的列?我能不能将EF放入某种只读模式,然后从实体中删除这些列?

我想这么做的原因是,通过仅保留我所需的数据模型中的列,我减少了模型在查询中返回的列数,并降低了模式更改时我的数据使用者出现错误的风险。

编辑:我的模式具有没有默认值的NOT NULL列的表。据我所知,我必须在我的edmx中包括这些列。在我的情况下,我只有只读上下文,所以我不希望这些列在我的edmx中出现。

如果我可以防止这些列被包含在数据模型中,我可以避免许多由于模式更改而引起的问题。到目前为止,我找到的唯一解决方案是通过指向一个没有这些列的“虚拟”数据库来构建数据模型!


如果我的表里有一个没有默认值的NOT NULL列,我就不能从我的edmx中删除它。Visual Studio会抛出构建错误。然而,由于我的数据上下文是只读的,所以对我来说无法插入行并不重要。 - Matthew
5个回答

4
根据MSDN的说法,QueryView正是为你所描述的情况而设计的。
在映射规范语言(MSL)中,QueryView元素定义了概念模型中实体类型或关联与底层数据库中表之间的只读映射。您可以定义查询视图以启用以下场景:
定义一个概念模型中不包括存储模型中实体的所有属性的实体。 这包括没有默认值并且不支持 null 值的属性。(页面上还有更多方案)
无法使用设计器完成此操作,但手动操作似乎很简单。
以下是相关MSDN文档的链接: https://msdn.microsoft.com/en-us/library/cc716798(v=vs.100).aspx 如果该链接失效,请搜索 "QueryView MSL"。

很遗憾,这不会起作用,因为QueryView是相对于底层模型表达的。更改模式会阻止我在底层模型中实例化对象 :( - Matthew

3

您是否正在寻找数据注释[NotMapped]

如果您在模型中的属性中使用它,它将不会传递到数据库。


使用这种方法的问题在于,如果支撑该列的模式发生更改(例如,从数据库中删除),那么模型在查询时仍将失败。 - Matthew

3
我可以防止由于更改架构而导致的许多问题。这最终归结于数据库设计。数据库需要针对您提出的升级场景进行不同的设计。将该列移出到一个可空的FK相关表可能是一个可行的选择,EF不需要进行任何未来更改。
但是,如果它们是非空的且没有默认值,我就必须拥有它们。
EF只是忠实地报告数据库中的内容,因为它的设计如此。
任何模式更改都可能影响许多因素,例如新约束、触发器和整个表更改。在设计器中隐藏列,然后希望它能在一个不同的模式-d数据库上运行是不明智的。
我个人遇到过不同步的EF设计模型,其中存在逻辑错误,可能以奇怪的方式影响代码。
我降低了架构更改会破坏数据消费者的风险。
这些“消费者”正如何访问数据?
任何真正的消费者都应该通过Web服务或工厂模式访问层进行访问,在那里数据只应该作为接口类型数据对象返回。因此,当数据库或模式更改时,返回的接口不会更改;因此,即使使用的具体对象不同,该架构更新也不会破坏任何安全的接口后面的消费者。
这不是您想要的答案,但这提供了两个实现相同目标的替代方案。

资源库通过返回只读的领域对象来混淆它们的数据访问模式。最终用户不知道EF是底层数据模型。问题在于,我可能会将一个完全无关紧要的列更改为资源库,这将导致其数据访问层中的对象无法实例化,因为数据模型不再与架构匹配。 - Matthew
@Matthew 好的,那么就需要在数据库设计上进行划分以应对未来的任何更改或手动修改模板;但这并没有真正回答你的问题。供你参考。谢谢。 - ΩmegaMan

3
如果你愿意使用代码优先而不是数据库优先,这可能会非常简单。
以微软的示例数据库 School 为例。它有一个名为 Course 的表,其中包含许多必填字段。但是可以将一个类映射到仅具有其中一小部分字段...
class Course
{
    public int CourseID { get; private set; }
    public string Title { get; private set; }
}

将数据添加到这个表格中,忽略必填字段 CreditsDepartmentID
在上下文的 OnModelCreating 重写中的流畅映射是:
modelBuilder.Entity<Course>().HasKey(a => a.CourseID);
modelBuilder.Entity<Course>().Property(a => a.CourseID)
                   .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

正如您所看到的,我使用了私有setter定义属性。EF对此没有任何问题,并向模型的任何使用者传达了模型是只读的信息。
除此之外,您甚至可以将非键属性映射为Computed:
modelBuilder.Entity<Course>().Property(a => a.Title)
            .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed);

现在不可能意外更新任何属性值,因为EF不会在UPDATE语句中包含它们。

0
你也可以通过从edmx存储模型部分删除不需要的属性来解决这个问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接