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

本文关键字:框架 接口 实体 属性 导航 | 更新日期: 2023-09-27 18:31:48

我正在开发一个应用程序,该应用程序可以使用实体框架和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

因此,使用基于接口类型的导航属性生成查询时似乎存在问题,

更新

我现在已经更改为代码第一个实体框架,使用一个模型来消除所有的烟雾和镜子。 不幸的是,我得到了完全相同的行为。

这是我的模型

    [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; }
    }

我还创建了一个 Db

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

我的数据库上下文有 2 个数据库集

 /// <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();

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

谢谢

任性

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

您可以使用

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

在您的数据库上下文中:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
        //one-to-many 
        modelBuilder.Entity<Entry>()
                    .HasRequired<EventbookEntry>(ev=> ev.EntryId ) 
                    .WithMany(ent => ent.EventbookEntries);     
}