我有几个类(无论如何都是这个例子),它首先使用代码与实体框架连接到数据库。
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);
}
是否有办法在覆盖默认行为时建立连接?
答案 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; }
除非您的视图是可更新的,否则每次尝试添加,更新或删除此集合中的任何客户时都会出现异常。映射到视图的Customer
和Contact
之间的映射关系后,您的导航属性应该可以正常工作。
SqlQuery
的问题在于它的工作方式。它返回分离的实体。分离的实体未连接到上下文,并且它们不会延迟加载其导航属性。您必须手动将每个Customer实例附加回上下文,然后再次需要DbSet
。