Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/320.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# IDbSet上没有FindAsync()方法<;T>;_C#_Entity Framework_Asp.net Identity - Fatal编程技术网

C# IDbSet上没有FindAsync()方法<;T>;

C# IDbSet上没有FindAsync()方法<;T>;,c#,entity-framework,asp.net-identity,C#,Entity Framework,Asp.net Identity,IDbSet接口中省略了FindAsync()方法有什么原因吗查找是接口的一部分,异步版本不可用似乎很奇怪。我需要转换到DbSet来访问它,这有点麻烦: User user = await ((DbSet<User>)db.Users) .FindAsync("de7d5d4a-9d0f-48ff-9478-d240cd5eb035"); User User=await((DbSet)db.Users) .FindAsync(“de7d5d4a-9d0f-48ff-9478

IDbSet
接口中省略了
FindAsync()
方法有什么原因吗<代码>查找是接口的一部分,异步版本不可用似乎很奇怪。我需要转换到
DbSet
来访问它,这有点麻烦:

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

如果您拥有
IDbSet
的使用者,我假设您这样做是因为您希望从使用者内部访问
FindAsync()
,那么一个简单的解决方案是创建您自己的界面,其中包括IDbSet,并包含您想要使用的
FindAsync()
方法:

public interface IAsyncDbSet<T> : IDbSet<T>
    where T : class
{
    Task<T> FindAsync(params Object[] keyValues);
}
公共接口IAsyncDbSet:IDbSet
T:在哪里上课
{
任务FindAsync(参数对象[]键值);
}
这就解决了不必转换到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
{
}
公共接口IMyAsyncDbSet
地点:班级
{
TEntity Add(TEntity实体);
tenty-Remove(tenty-entity);
//根据需要从IDbSet复制其他方法。
任务FindAsync(参数对象[]键值);
}
公共类MyDbSet:DbSet,IMyAsyncDbSet
T:在哪里上课
{
}

这是一个适配器模式,真的。它将代码期望的接口与实体框架提供的接口分离。现在,它们是相同的-这就是实现除了继承
DbSet
之外什么都不做的原因。但后来他们可能会分歧。在这一点上,您仍然可以使用最新的DbSet而不破坏代码。

使用此扩展解决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;
        });
    }
}
//
///IDbSet扩展
/// 
公共静态类IDbSetExtension
{
公共静态任务FindAsync(此IDbSet集合,参数对象[]keyValues)
地点:班级
{
返回任务。运行(()=>
{
var entity=set.Find(键值);
返回实体;
});
}
}

以下是我如何在我们的一个项目中解决这一问题的:

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);
            }
        }
    }
}
使用System.Threading.Tasks;
命名空间System.Data.Entity
{
公共静态类IDbSetExtensions
{
/// 
///如果可能,异步查找具有给定主键值的实体
///否则,将同步查找实体。
///如果上下文中存在具有给定主键值的实体,则它是
///立即返回,无需向商店提出请求。否则
///向存储区请求具有给定主键值的实体
///如果找到该实体,则将其附加到上下文并返回。如果没有
///在上下文或存储中找到实体,然后返回null。
/// 
/// 
/// 
///要查找的实体的主键的值。
///表示异步查找操作的任务。任务结果包含
///已找到实体,或为null。
/// 
公共静态异步任务FindAsync(此IDbSet@this,params对象[]keyValues)
地点:班级
{
DbSet thisdset=@此为DbSet;
if(thisdset!=null)
{
返回wait thisdset.FindAsync(keyValues);
}
其他的
{
返回@this.Find(keyValues);
}
}
}
}

可以考虑将查找方法封装在异步模式之上,这将提供卸载(并且没有真正的异步方法的可扩展性)。然而,调用方必须意识到这一点,以确保在调用可能会干扰的FindAsync方法之后,他们不会调用上下文中的方法。然而,让调用者知道特定的实现并不是一个很好的设计,因为它很容易导致问题。对于OP,IDbSet是一个DbSet,因此调用将是异步的

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

我相信现在正确的方法(从EF 6开始)是从DbSet继承,而不是实现IDbSet。

请将此作为一个单独的问题,因为答案是肯定的,但代码将无法放入注释中。我创建了一个新问题:您可以发布代码作为新问题的答案吗?此方法使用“同步上的异步”“模式,这是一种反模式。如果工作应该异步完成,那么就应该使用查询提供程序固有的异步操作。生成一个线程来执行IO工作是一个大问题,至少在库代码中是这样。在asp.net上下文中,生成线程也会对性能造成不利影响,因为您基本上是从asp窃取一个可用于服务请求的线程。情况并非总是如此。Find方法有点特殊,因为“如果上下文中存在具有给定主键值的实体,那么它将立即返回,而无需向存储发出请求。”非常感谢实现,我发现这样做更干净。我有一个问题:我看到我们在“DbSet thisdset=(DbSet)@this;”时实现了“取消装箱”。这个拆箱很贵吗?它只是一个显式的强制转换,所以不会太贵。对代码的优化是使用“as”操作符。只有当值类型从类型“object”或接口转换为值类型时才会取消装箱。RonDeijkers:谢谢!我正在使用Resharper,它对它做了一些很酷的处理:这就是发生的事情(在方法内部):var set=@this as DbSet;if(set==n