EF Code First - 为1:1关系添加SQL View

时间:2014-08-01 19:32:36

标签: entity-framework ef-code-first

我开始研究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实体和一个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模型,因为它存在以测试数据库的第一个进程。我添加了使用我的代码第一个逻辑和我添加的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>

其他所有(实体)看起来都一样。我使用控制台应用程序进行了快速测试,看起来效果很好。

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

1 个答案:

答案 0 :(得分:0)

每次应用程序运行时,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> Enable-MIgrations

    PM> Add-Migration AddBarsView

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

    PM> Update-Database

您的视图已准备好使用。