简体   繁体   English

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

[英]Correctly use Interfaces on Navigation Properties Entity Framework

I am developing an application which can connect to multiple similar databases using entity framework and Devart. 我正在开发一个应用程序,它可以使用实体框架和Devart连接到多个类似的数据库。 I have done this by creating some interfaces which my EF models implement and it works ok, however I have come across a performance issue, 我已经通过创建我的EF模型实现的一些接口并且它工作正常,但是我遇到了性能问题,

Take the following Interfaces 采用以下接口

public interface IEventBookEntry {

     int EntryId { get;set;}

     int EventBookId {get;set;}

     bool Flagged {get;set;

     IEntry Entry {get;set;}

}

and

public Interface IEntry {

    int EntryId {get;set;}

    DateTime EntryTimestamp {get;set;}

    ICollection<IEventBookEntry> EventBookEntries {get;set;}

}

My two entity models (which connect to different databases) implement the above interfaces. 我的两个实体模型(连接到不同的数据库)实现了上述接口。

This means that i can write queries in my BLL layer which can run against either entity model, great stuff! 这意味着我可以在我的BLL层中编写查询,这些查询可以针对任一实体模型运行,很棒!

Let's take the following Linq method query: 我们采用以下Linq方法查询:

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

The above code gets all the eventbook entries where eventBookId == 123 and the timestamp of the entry is within the past 3 days. 上面的代码获取eventBookId == 123的所有eventbook条目,并且条目的时间戳在过去3天内。

for completeness, here is the detail of the "GetList" method in the eventBookRepository 为了完整性,这里是eventBookRepository中“GetList”方法的细节

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

You would expect the sql generated behind the scenes for this to be something like this 你会期望在幕后生成的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

Unfortunately, what happens is that we do not get a single query with a join to entries, what happens instead is that we get one query which retrieves all EventBookEntries where EventBookId = 123 then a query per row returned which gets each entry. 不幸的是,发生的事情是我们没有获得带有条目连接的单个查询,而是我们得到一个查询,它检索所有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

So it looks like there's a problem when generating queries using navigation properties based on interface types, 所以看起来在使用基于接口类型的导航属性生成查询时会出现问题,

Update 更新

I have now changed to Code First Entity Framework with one model to remove all the smoke and mirrors. 我现在已经改为使用一个模型的Code First Entity Framework来删除所有的烟雾和镜子。 unfortunately I get exactly the same behavior. 不幸的是,我得到完全相同的行为。

Here's my model 这是我的模特

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

    }

and

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

I've also created a Db 我也创建了一个Db

So now I just use the dbContext directly and change my database provider which works a treat, however I still get the same behaviour! 所以现在我只是直接使用dbContext并更改我的数据库提供程序,这是一种享受,但我仍然得到相同的行为!

My DbContext has 2 DbSets 我的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; }

Here's my linq method query 这是我的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();

My Question is how do you implement interfaces on navigation properties in such a way as to ensure entity framework will use inner joins in queries rather than the behavior exhibited above? 我的问题是如何在导航属性上实现接口,以确保实体框架将在查询中使用内部联接而不是上面显示的行为?

Thanks 谢谢

Wayward 任性

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

in your DbContext : 在你的DbContext中:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM