将DbSet <entity>转换为其DbSet <ientity>而不将所有实体都拉入内存</ientity> </entity>

时间:2013-11-30 11:20:04

标签: c# linq entity-framework

我的问题是,我正在使用的系统期望数据为IQuearable<IEntity>,而entityframework为我提供的数据为IQueryable<Entity>

这是我需要实现的界面:

public IQueryable<T> GetData<T>() where T : class, IData {}

我创建了一个DbSet作为context.Set(MyEntityType),其中MyEntityType是typeof(Entity)。

我一直在尝试一些事情,不知道如何解决这个问题。 (它的所有自动生成的代码来自codedom,但是在下面做了一个测试,看它可以工作,但还没有工作)

我做了一个测试包装,问题就在这里LINQ to Entities only supports casting EDM primitive or enumeration types如果我可以做这项工作,我也可以让我的其他部分工作。

public class DbSetWrapper<C1Data,Entity>
    where C1Data : IData 
    where Entity: class
{

    public DbSetWrapper(C1AzureStoreRPContext context)
    {
        Data = context.Set<Entity>().Cast<C1Data>();
    }
    public IQueryable<C1Data> Data { get; private set; }
}

public class C1AzureStoreRPContext : DbContext
{
    static C1AzureStoreRPContext()
    {
        Database.SetInitializer<C1AzureStoreRPContext>(null);
    }
    // Methods
    public C1AzureStoreRPContext(string connectionstring)
        : base(connectionstring)
    {

    }

    // Properties

    public DbSet<AzureStoreSubscriptionWrapper> AzureStoreSubscriptions { get; set; }
}
 public interface IAzureStoreSubscription : IData, IEntityFrameworkProvided {}
 public class AzureStoreSubscriptionWrapper : AzureStoreSubscription, IAzureStoreSubscription { }

 using (var c1 = new C1AzureStoreRPContext("opencms-sql-connection"))
 {
    var wrap = new DbSetWrapper<IAzureStoreSubscription, AzureStoreSubscriptionWrapper>(c1);
    Log.LogInformation("EF", string.Format("hello {0}", wrap.Data.ToList().Count));
 }

我不想将所有数据都拉到内存并进行投射,是否有其他解决方案?

2 个答案:

答案 0 :(得分:3)

IQueryable<T>是协变的,所以不要试图将DbSet<SubType>强制转换为DbSet<SuperType>,只需指定:

Data = context.Set<Entity>(); // .AsQueryable() not needed but does make it more readable

当然,这取决于Entity实现C1Data,这不能保证基于您的泛型类定义(这不好)。要解决此问题,请更改Entity的类型约束,如下所示:

where Entity: C1Data

答案 1 :(得分:1)

我最终在我的应用程序中使用的代码是:

public IQueryable<T> GetData<T>() where T : class, IData
{
    var factory = EntityFrameworkConfiguration.TypeFactory[typeof(T)];
    var context = factory.Item2();
    ThreadDataManager.GetCurrentNotNull().OnDispose += () =>
    {             
        context.Dispose();
    };

    var method = typeof(DbContext).GetMethod("Set", new Type[0]).MakeGenericMethod(factory.Item1);
    IQueryable<T> genericItem = (IQueryable < T >)method.Invoke(context, new object[0]);
    return genericItem;
}

请注意,ThreadDataManager是我正在集成的系统的一部分。