簡體   English   中英

IDbSet上沒有FindAsync()方法<T>

[英]No FindAsync() method on IDbSet<T>

有沒有理由從IDbSet<T>接口中省略FindAsync()方法? Find是界面的一部分,異步版本不可用似乎很奇怪。 我需要轉換為DbSet<T>來訪問它,這有點麻煩:

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

如果您擁有IDbSet<T>的使用者,我認為您這樣做是因為您希望從使用者中訪問FindAsync() ,那么一個簡單的解決方案是創建您自己的包含IDbSet的接口並包含任何FindAsync()您要使用的方法:

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

這解決了不必轉換為DbSet的問題 - 順便說一下,它破壞了合同編碼的抽象性好處。 但這也引入了一系列問題。

需要更多工作的更好的解決方案(imo)是定義一個接口,該接口僅包含您要在DbSet對象中使用的成員,在實現接口時子類DbSet,然后在代碼中使用該接口:

public interface IMyAsyncDbSet<TEntity>
    where TEntity : class
{
    TEntity Add(TEntity entity);
    TEntity Remove(TEntity entity);

    // Copy other methods from IDbSet<T> as needed.

    Task<Object> FindAsync(params Object[] keyValues);
}

public class MyDbSet<T> : DbSet<T>, IMyAsyncDbSet<T>
    where T : class
{
}

這是一個適配器模式,真的。 它將您的代碼所期望的接口與Entity Framework提供的接口分離。 現在,它們是相同的 - 這就是為什么除了繼承DbSet<T>之外什么都不做。 但后來他們可能會分歧。 此時,您仍然可以使用最新的DbSet而不會破壞您的代碼。

以下是我在其中一個項目中解決這個問題的方法:

using System.Threading.Tasks;

namespace System.Data.Entity
{
    public static class IDbSetExtensions
    {
        /// <summary>
        /// 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.
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="this"></param>
        /// <param name="keyValues">The values of the primary key for the entity to be found.</param>
        /// <returns>A task that represents the asynchronous find operation. The task result contains 
        /// the entity found, or null.</returns>
        /// <exception cref="System.InvalidOperationException"></exception>
        public static async Task<TEntity> FindAsync<TEntity>(this IDbSet<TEntity> @this, params object[] keyValues)
        where TEntity : class
        {
            DbSet<TEntity> thisDbSet = @this as DbSet<TEntity>;
            if (thisDbSet != null)
            {
                return await thisDbSet.FindAsync(keyValues);
            }
            else
            {
                return @this.Find(keyValues);
            }
        }
    }
}

可以考慮將Find方法包裝在異步同步模式中,該模式將提供卸載(並且不像真正的異步方法那樣具有可伸縮性)。 但是,調用者必須知道這一點,以確保在調用可能會干擾的FindAsync方法后,他們不會在上下文中調用方法。 讓調用者意識到特定的實現並不是一個非常好的設計,但是因為它很容易導致問題。 對於OP,IDbSet是DbSet,因此調用將是異步的。

我相信這些天(因為EF 6)的正確方法涉及從DbSet繼承而不是實現IDbSet。

將FindAsync方法更改為FirstOrDefaultAsync(x => x.Id == yourId);

使用此擴展來解決FindAsync問題

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM