使用SQL查询使用实体框架建立外键连接

时间:2012-01-25 15:18:43

标签: entity-framework-4

我有几个类(无论如何都是这个例子),它首先使用代码与实体框架连接到数据库。

public class Customer
{
    [Key]
    public long CustomerId { get; set; }
    public string CompanyName { get; set; }
    ...
    public virtual List<Contact> Contacts { get; set; }
}

public class Contact
{
    [Key]
    public long ContactId { get; set; }
    public string Forename { get; set; }
    ...
    public long CustomerId { get; set; }

    public virtual Customer Customer { get; set; }
}

当我在上下文类中直接将它们连接到数据库时,外键关系很好地连接起来,我可以从客户类中访问联系人集合。

class RemoteServerContext : DbContext 
{
    public DbSet<Customer> Customers { get; set; }
    public DbSet<Contact> Contacts { get; set; }
    ...
}

我的问题是这些数据库表被各种不同的系统使用并且非常庞大。为了提高效率,我已经覆盖了默认行为以指向视图(以及其他地方的存储过程),而不是直接在表中。

    public IEnumerable<Customer> Customers ()
    {
        return Database.SqlQuery<Customer>("SELECT * FROM vw_CustomerList");
    }

    public IEnumerable<Contact> Contacts()
    {
        return Database.SqlQuery<Contact>("SELECT * FROM vw_ContactsList");
    }

我确保在每个视图中都包含了外键字段:CustomerId和ContactId。

当我这样做时,类连接似乎丢失了 - 当我钻入应该指向另一个对象的任何一个对象时,总是为空。我试图设置外键字段应指向的内容,但这似乎也没有帮助。

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Contact>().HasRequired(p => p.Customer)
            .WithMany()
            .HasForeignKey(k => k.CustomerId);
    }

是否有办法在覆盖默认行为时建立连接?

1 个答案:

答案 0 :(得分:1)

在这种情况下没有压倒一切。如果你删除了

public DbSet<Customer> Customers { get; set; }

并将其替换为

public IEnumerable<Customer> Customers ()
{
    return Database.SqlQuery<Customer>("SELECT * FROM vw_CustomerList");
}

你已完全改变了这种行为。第一个使用EF的实体和全部功能。第二个是执行自定义SQL的辅助工具。在OnModelCreating中没有第一个或没有定义实体的第二个根本不使用Customer作为映射实体 - 它将它用作任何普通类(只有映射的实体可以使用延迟加载等功能)。

由于您的客户现在已映射到视图,因此您无法使用以前与表一起使用的Customer类。您必须通过欺骗EF来定义Customer到视图的映射:

modelBuilder.Entity<Customer>().ToTable("vw_ContactsList"); // EF code fist has no view mapping

一旦你有了这个,你可以再试一次:

public DbSet<Customer> Customers { get; set; }

除非您的视图是可更新的,否则每次尝试添加,更新或删除此集合中的任何客户时都会出现异常。映射到视图的CustomerContact之间的映射关系后,您的导航属性应该可以正常工作。

SqlQuery的问题在于它的工作方式。它返回分离的实体。分离的实体未连接到上下文,并且它们不会延迟加载其导航属性。您必须手动将每个Customer实例附加回上下文,然后再次需要DbSet