在导航属性实体框架上正确使用接口

Posted

技术标签:

【中文标题】在导航属性实体框架上正确使用接口【英文标题】:Correctly use Interfaces on Navigation Properties Entity Framework 【发布时间】:2016-05-01 16:19:34 【问题描述】:

我正在开发一个应用程序,它可以使用实体框架和 Devart 连接到多个类似的数据库。我通过创建一些我的 EF 模型实现的接口来做到这一点,它工作正常,但是我遇到了性能问题,

采取以下接口

public interface IEventBookEntry 

     int EntryId  get;set;

     int EventBookId get;set;

     bool Flagged get;set;

     IEntry Entry get;set;


public Interface IEntry 

    int EntryId get;set;

    DateTime EntryTimestamp get;set;

    ICollection<IEventBookEntry> EventBookEntries get;set;


我的两个实体模型(连接到不同的数据库)实现了上述接口。

这意味着我可以在我的 BLL 层中编写可以针对任一实体模型运行的查询,很棒!

我们来看看下面的 Linq 方法查询:

   var eventBookEntries = new EventBookRepository().GetList(eb => eb.EventBookId == 123 && eb.Entry.EntryTimestamp > DateTime.Now.AddDays(-3));

上面的代码获取了 eventBookId == 123 并且该条目的时间戳在过去 3 天内的所有事件簿条目。

为了完整起见,这里是 eventBookRepository 中“GetList”方法的详细信息

public IList<IEventBookEntry> GetList(Func<IEventBookEntry, bool> where, params Expression<Func<IEventBookEntry, object>>[] navigationProperties)
        
            return new EventBookEntities().EventBookEntries.Where(where).ToList();
        

你会期望在后台生成的 sql 是这样的

 SELECT Extent1.EntryId, Extent1.EventBookId, Extent1.Flagged 
  FROM EventBookEntries Extent1
  INNER JOIN Entries Extent2 ON Extent1.EntryId = Extent2.EntryId
  WHERE Extent1.EventBookId = 123
  AND Extent2.EntryTimestamp > 22/01/2016

不幸的是,发生的情况是我们没有得到一个与条目连接的查询,相反,我们得到一个查询,它检索所有 EventBookEntries,其中 EventBookId = 123,然后每行返回一个查询,获取每个条目。

SELECT Extent1.EntryId, Extent1.EventBookId, Extent1.Flagged 
FROM EventBookEntries Extent1
WHERE Extent1.EventBookId = 123


SELECT Extent1.EntryId, Extent1.EntryTimestamp
FROM Entries Extent1
WHERE Extent1.EntryId = :EntityKeyValue1

所以看起来在使用基于界面类型的导航属性生成查询时出现了问题,

更新

我现在已更改为 Code First Entity Framework,使用一个模型来消除所有的烟雾和镜子。不幸的是,我得到了完全相同的行为。

这是我的模型

    [Table("ENTRIES")]
    public class Entry
    
        public Entry()
        
           EventbookEntries = new List<EventbookEntry>();
        

        [Key, Column("ENTRY_ID", Order = 1)]
        public long EntryId  get; set; 

        [Column("ENTRY_TIMESTAMP")]
        public DateTime EntryTimestamp  get; set; 


        [ForeignKey("EntryId")]
        public virtual ICollection<EventbookEntry> EventbookEntries get;set;

    

    [Table("EVENT_BOOK_ENTRIES")]
    public class EventbookEntry
    

        [Key, Column("ENTRY_ID", Order = 1)]
        public long EntryId  get; set; 

        [Key, Column("EVENT_BOOK_ID", Order = 2)]
        public long EventbookId  get; set; 

        [ForeignKey("EntryId")]
        public virtual Entry Entry  get; set; 
    

我还创建了一个数据库

所以现在我只是直接使用 dbContext 并更改我的数据库提供程序,这很有效,但是我仍然得到相同的行为!

我的 DbContext 有 2 个 DbSet

 /// <summary>
 /// Gets or sets the entries.
 /// </summary>
 /// <value>The entries.</value>
 public DbSet<Entry> Entries  get; set; 

/// <summary>
/// Gets or sets the eventbook entries.
/// </summary>
/// <value>The eventbook entries.</value>
public DbSet<EventbookEntry> EventbookEntries  get; set; 

这是我的 linq 方法查询

var start = DateTime.Now.AddDays(-20);
var eventBookId = 124;

var eventbookEntries = new EventBookContext().EventbookEntries.Where(eb=> eb.EventbookId == eventBookId && eb.Entry.EntryTimestamp > start).ToList();

我的问题是,您如何在导航属性上实现接口,以确保实体框架将在查询中使用内部连接,而不是上面展示的行为?

谢谢

任性

【问题讨论】:

什么是GetList()?你能展示一下存储库的实现吗? 我不知道 Devart 的数据提供者,但看起来这种行为是支持接口的权衡。 您说“连接到不同的数据库”——您的意思是 Entry 在一个数据库中,而 EventBookEntry 在另一个数据库中? 不,我的意思是它们都在同一个数据库中,我只是使用不同的数据库提供程序 【参考方案1】:

您可以使用 Fluent API (http://www.entityframeworktutorial.net/code-first/configure-one-to-many-relationship-in-code-first.aspx) 使用关系

在您的 DbContext 中:

protected override void OnModelCreating(DbModelBuilder modelBuilder)

        //one-to-many 
        modelBuilder.Entity<Entry>()
                    .HasRequired<EventbookEntry>(ev=> ev.EntryId ) 
                    .WithMany(ent => ent.EventbookEntries);     

【讨论】:

以上是关于在导航属性实体框架上正确使用接口的主要内容,如果未能解决你的问题,请参考以下文章

实体框架上的急切加载导航属性

实体框架Linq查询:如何在多个导航属性上从何处选择并从第三个导航属性中选择

如何修复实体框架中的“无法确定导航属性表示的关系”错误

如何在实体框架模型中使用通用导航属性?

LINQ 实体 Where 子句不在正确位置

实体框架对导航属性的约束