IDbSet 上没有FindAsync()方法

有没有理由从IDbSet接口中省略FindAsync()方法? Find是界面的一部分,异步版本不可用似乎很奇怪。 我需要DbSet转换为DbSet来访问它,这有点麻烦:

 User user = await ((DbSet)db.Users) .FindAsync("de7d5d4a-9d0f-48ff-9478-d240cd5eb035"); 

如果您拥有IDbSet的使用者,我认为您这样做是因为您希望从使用者中访问FindAsync() ,那么一个简单的解决方案是创建您自己的包含IDbSet的接口并包含任何FindAsync()您要使用的方法:

 public interface IAsyncDbSet : IDbSet where T : class { Task FindAsync(params Object[] keyValues); } 

这解决了不必转换为DbSet的问题 – 顺便说一下,它破坏了合同编码的抽象性好处。 但这也引入了一系列问题。

需要更多工作的更好的解决方案(imo)是定义一个接口,该接口仅包含您要在DbSet对象中使用的成员,在实现接口时子类DbSet,然后在代码中使用该接口:

 public interface IMyAsyncDbSet where TEntity : class { TEntity Add(TEntity entity); TEntity Remove(TEntity entity); // Copy other methods from IDbSet as needed. Task FindAsync(params Object[] keyValues); } public class MyDbSet : DbSet, IMyAsyncDbSet where T : class { } 

这是一个适配器模式,真的。 它将您的代码所期望的接口与Entity Framework提供的接口分离。 现在,它们是相同的 – 这就是为什么除了inheritanceDbSet之外什么都不做。 但后来他们可能会分歧。 此时,您仍然可以使用最新的DbSet而不会破坏您的代码。

以下是我在其中一个项目中解决这个问题的方法:

 using System.Threading.Tasks; namespace System.Data.Entity { public static class IDbSetExtensions { ///  /// If possible asynchronously finds an entity with the given primary key values /// otherwise finds the entity synchronously. /// If an entity with the given primary key values exists in the context, then it is /// returned immediately without making a request to the store. Otherwise, a /// request is made to the store for an entity with the given primary key values /// and this entity, if found, is attached to the context and returned. If no /// entity is found in the context or the store, then null is returned. ///  ///  ///  /// The values of the primary key for the entity to be found. /// A task that represents the asynchronous find operation. The task result contains /// the entity found, or null. ///  public static async Task FindAsync(this IDbSet @this, params object[] keyValues) where TEntity : class { DbSet thisDbSet = @this as DbSet; if (thisDbSet != null) { return await thisDbSet.FindAsync(keyValues); } else { return @this.Find(keyValues); } } } } 

有人可能会考虑将Find方法包装在异步同步模式中,该模式将提供卸载(并且不像真正的异步方法那样具有可伸缩性)。 但是,调用者必须知道这一点,以确保在调用可能会干扰的FindAsync方法后,他们不会在上下文中调用方法。 让调用者意识到特定的实现并不是一个非常好的设计,但是因为它很容易导致问题。 对于OP,IDbSet是DbSet,但是调用将是异步的。

我相信这些天(因为EF 6)的正确方法涉及从DbSetinheritance而不是实现IDbSet。

将FindAsync方法更改为FirstOrDefaultAsync(x => x.Id == yourId);

使用此扩展来解决FindAsync问题

 ///  /// IDbSet extension ///  public static class IDbSetExtension { public static Task FindAsync(this IDbSet set, params object[] keyValues) where TEntity : class { return Task.Run(() => { var entity = set.Find(keyValues); return entity; }); } }