协变参数数组

时间:2015-12-17 17:28:38

标签: generics c#-4.0 covariance generic-collections

我有一个界面:

IReadOnlyList<TEntity> Execute<TEntity>(ILambdaQuery<TEntity> query, params ILambdaQuery<TAssociatedEntity>[] associations) where TAssociatedEntity : class, IAggregateRoot;

该接口用于在存储库中执行查询。其中TEntity是您期望的类型以及您要查询的内容,TAssociatedEntity是您想要运行的其他查询,并且将与返回的TEntity结果相结合。例如

var courseQuery = LambdaQuery<Course>(c => c.Id == id);

var studentsQuery = LambdaQuery<Student>(s => s.Courses.Any(c => c.id == id));

var instructorsQuery = LambdaQuery<Instructor>(i => i.Courses.Any(c => c.id == id));

var courses = this.repo.Execute<Course>(courseQuery, studentsQuery, instructorsQuery);

我的问题围绕这个参数:

params ILambdaQuery<TAssociatedEntity>[] associations

从示例中可以看出,associations数组可以有不同类型的TAssociatedEntity。那么如何告诉编译器?

上面的界面不能完成这项工作。编译器说无法找到命名空间名称'TAssociatedEntity'的类型......

这是不可能的吗?那里有什么想法吗?

编辑 - 要求提供更多信息:

LambdaQuery类将lambda表达式子句和关联实体存储在eager fetch中。其中大量传递给存储库Execute方法,该方法执行:

    public IReadOnlyList<TEntity> Execute(ILinqQuery<TEntity> query, params ILinqQuery<TAssociatedEntity>[] associations)
    {
        var queryOver = this.GetSession().QueryOver<TEntity>().Where(query.WhereClause);

        query.FetchExpressions.ToList().ForEach(expression => queryOver = queryOver.Fetch(expression).Eager);

        var future = queryOver.Future<TEntity>();

        foreach (ILinqQuery<TEntity> association in associations)
        {
            var queryOverAssociation = this.GetSession().QueryOver<TEntity>().Where(association.WhereClause);

            association.FetchExpressions.ToList().ForEach(expression => queryOverAssociation = queryOverAssociation.Fetch(expression).Eager);

            queryOverAssociation.Future<TEntity>();
        }

        return this.ExecuteInTransaction(() => future.ToList());
    }

它以批处理方式运行查询和任何关联的查询,并返回填写了任何位的请求的TEntity。

编辑 - 更多信息

我对nHibernate并不精彩。但在我的简单术语中,使用Future()执行的任何操作都会被延迟,直到调用ToList()为止。

所以,如果我有:

class Person
{
   public string Id { get; set; }
   public List<Arm> Arms { get; set; }
   public List<Leg> Legs { get; set; }
}

class Arm
{
   public string Id { get; set; }
   public List<Hand> Hands { get; set; }
}

class Leg
{
   public string Id { get; set; }
   public List<Foot> Feet { get; set; }
}

因此,如果为一个人的TEntity调用了Execute方法,并且一个人拥有一组手臂,每个手臂都有一只手和一组腿,每个腿都有一个脚,那么我们可能会有一个执行看起来像:

LambdaQuery<Person> personQuery = new LambdaQuery<Person>(t => t.Id == "123");
LambdaQuery<Arm> armQuery = new LambdaQuery<Arm>(t => t.Person.Id == "123", t => t.Hands);

Person person = personRepository.Execute(personQuery, armQuery);

然后它会批量发送以下内容到数据库:

SELECT * FROM person WHERE personId = '123';
SELECT * FROM arms a JOIN hands h ON h.armId = a.armId WHERE a.personId = "123"

一个(无腿)Person对象将从Execute方法返回:

Person
------
{ 
  Id : "123", 
  Arms : [ { Id : "ARM1", Hands : [ { Id : "HAND1" }, { Id : "HAND2" } ] } ], 
  Legs: null 
}

1 个答案:

答案 0 :(得分:0)

您尚未将TAssociatedEntity类型声明为泛型类型,这可以通过两种方式完成。

修改方法(这可能是你想要做的)

IReadOnlyList<TEntity> Execute<TEntity,TAssociatedEntity>...

或如果TAssociatedEntity必须是协变的接口。

public interface IDontKnow<in TAssociatedEntity>