【问题标题】:EF Code First - adding SQL View for 1:1 relationshipEF Code First - 为 1:1 关系添加 SQL 视图
【发布时间】:2014-08-01 19:32:36
【问题描述】:

我开始使用 EF Code First 方法并自动生成数据库。现在我想添加另一个映射到 SQL 视图而不是表的实体。我正在使用视图,因为数据(员工信息)位于单独的数据库中。我添加了视图并创建了一个实体,但我不断收到上下文已更改的错误,我需要手动删除/更新数据库或调用 SetInitializer 方法。我认为问题在于我的模型定义或我对数据库更改的假设。

基本实体是 AppUser(应用程序特定用户)和 vEmp(查看员工数据)。 AppUser 实体不多:

public class AppUser
{
    public AppUser()
    {
    }

    [Key]
    public int AppUserId { get; set; }
    [MaxLength(75)]
    public string ntUserDomainId { get; set; }
    public bool isActive { get; set; }

    public virtual vEmp vEmp { get; set; } // this was commented out at first to generate tables

}

vEmp 实体定义如下:

public class vEmp
{
    [Key, ForeignKey("AppUser")]
    public int AppUserId { get; set; }
    public string empName { get; set; }
    public string empStatus { get; set; }
    public string orgid { get; set; }
    public string email { get; set; }
    public string ntUserDomainId { get; set; }

    public virtual AppUser AppUser { get; set; }

}

为了完成这项工作,我在 AppUser 中注释掉了导航属性,以便 EF 生成表。然后我取消了导航属性的注释并遇到了错误。如果我尝试保留导航属性,则 EF 假定一个表并将“vEmp”创建为一个表。该视图实际上匹配用户 NT ID 以形成查询结果 - 我们使用 Windows 身份验证,因此每个用户在 AppUser 表中都有他们的 NT ID。

据我所知,[Key, ForeignKey("AppUser")] 行应该告诉 EF 如何管理关系。我唯一的猜测是 EF 希望创建一个交叉引用表以在两者之间进行映射。

我还想知道是否更简单的方法是先使用 DB 并使用 EF 从 DB 生成模型。我使用自动生成的 EDMX 使用类似的 vEmp entitye 和 AppUser 实体进行了一个测试项目,并且在我手动建立关联后似乎可以正常工作。我们有很多共享数据库,因此使用视图将很普遍,我想知道代码优先在这种情况下是否难以使用。

更新

我想我有证据证明 EF 想要创建一个表。我玩弄了迁移,这就是我所看到的:

public override void Up()
{
    CreateTable(
        "dbo.vEmps",
        c => new
            {
                AppUserId = c.Int(nullable: false),
                empName = c.String(),
                empStatus = c.String(),
                orgid = c.String(),
                email = c.String(),
                ntUserDomainId = c.String(),
            })
        .PrimaryKey(t => t.AppUserId)
        .ForeignKey("dbo.AppUsers", t => t.AppUserId)
        .Index(t => t.AppUserId);

}

如果我理解正确,EF 似乎看不到名为“vEmp”的 SQL 视图,而是想创建一个表。这是否意味着代码首先不适用于 SQL 视图?

更新 2 在多次尝试使代码优先语法工作失败后,我从数据库创建了一个 edmx 模型,因为它存在以测试 DB 优先进程。我添加了使用我的代码优先逻辑和我添加的 SQL 视图创建的所有表。然后我刚刚创建了一个与建模工具的关联,从表 AppUser 到视图 vEmp。建模工具似乎已创建此代码:

<Association Name="vEmpAppUser">
  <End Type="JobControlModel.vEmp" Role="vEmp" Multiplicity="1" />
  <End Type="JobControlModel.AppUser" Role="AppUser" Multiplicity="1" />
  <ReferentialConstraint>
    <Principal Role="AppUser">
      <PropertyRef Name="AppUserId" />
    </Principal>
    <Dependent Role="vEmp">
      <PropertyRef Name="AppUserId" />
    </Dependent>
  </ReferentialConstraint>
</Association>

其他一切(实体)看起来都一样。我使用控制台应用程序进行了快速测试,它似乎工作正常。

我不确定为什么这似乎适用于 DB 优先方法而不是代码优先方法。实体的定义相同。唯一的问题是尝试首先使用代码重新创建数据库首先调用的“关联”。

【问题讨论】:

    标签: entity-framework ef-code-first


    【解决方案1】:

    每次应用程序运行时,EF 都会首先获取最后的迁移历史记录。如果你使用分析器检查它,你会得到类似的东西

    exec sp_executesql N'SELECT TOP (1) 
        [Project1].[C1] AS [C1], 
        [Project1].[MigrationId] AS [MigrationId], 
        [Project1].[Model] AS [Model], 
        [Project1].[ProductVersion] AS [ProductVersion]
        FROM ( SELECT 
            [Extent1].[MigrationId] AS [MigrationId], 
            [Extent1].[Model] AS [Model], 
            [Extent1].[ProductVersion] AS [ProductVersion], 
            1 AS [C1]
            FROM [dbo].[__MigrationHistory] AS [Extent1]
            WHERE [Extent1].[ContextKey] = @p__linq__0
        )  AS [Project1]
        ORDER BY [Project1].[MigrationId] DESC',N'@p__linq__0 nvarchar(4000)',@p__linq__0=N'TheProjectName.TheContextName'
    go
    

    在迁移历史表中有某种校验和,用于存储有关上下文的信息,它可能会尝试与应用程序中的上下文进行比较。

    如果您从 EF 生成数据库,然后您手动修改了数据库并且还修改了类/实体中的相同更改,您还需要运行迁移以更新迁移历史记录表。

    您可以查看this article以获取更多说明。

    更新

    您可以运行空迁移来保存当前的DbContext 状态。

    例如你在数据库中添加了这个视图

    create view Bars
    as
       select Id, Name from Foos
    

    并且您已经创建了与视图(类型和任何约束)匹配的类和配置。

    public class Bar
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
    
    public DbSet<Bar> Bars {get;set;}
    
    modelBuilder.Entity<Bar>().ToTable("Bars");
    

    你需要做的是

    • 添加迁移

      PM&gt; Enable-MIgrations

      PM&gt; Add-Migration AddBarsView

    • 打开AddBarsView,清空UpDown方法,然后运行迁移

      PM&gt; Update-Database

    您的视图将可以使用。

    【讨论】:

    • 我使用EF创建了数据库,然后添加了SQL视图,然后尝试更新实体模型以使用SQL视图。 EF 似乎无法识别 SQL 视图,而是希望创建一个同名的新表。或者,我对实体模型的更改不正确。
    • @pretzelb,您确定视图列和类属性相互匹配吗?
    • 列和属性似乎匹配。我想也许问题是我的观点是 vEmp,它想要 vEmp,但我重新创建了数据库,但这仍然没有帮助。我认为问题在于 EF 想要创建一个 FK,而这样做的唯一方法是使用一个表,因此即使视图 vEmps 已经存在,迁移也希望创建一个名为 vEmps 的表。
    猜你喜欢
    • 1970-01-01
    • 2011-08-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-10
    相关资源
    最近更新 更多