C# LINQ到实体-动态生成where谓词

C# LINQ到实体-动态生成where谓词,c#,linq-to-entities,linq-expressions,C#,Linq To Entities,Linq Expressions,我有这个: public void AssertReadWorks<T>( IRepository<T> repository, T entity, Expression<Func<T, T, bool>> keyComparer) where T : class { entity = repository.GetAll().Single(x => x.Id == entity.Id); } [TestM

我有这个:

public void AssertReadWorks<T>(
    IRepository<T> repository, 
    T entity, 
    Expression<Func<T, T, bool>> keyComparer) where T : class
{
    entity = repository.GetAll().Single(x => x.Id == entity.Id);
}

[TestMethod]
public void ReadTest_DataFieldGroup()
{
    AssertReadWorks(
            _unitOfWork.DataFieldSetRepository, 
            new DataFieldSet { Label = "test", Title = "test" }, 
            (a, b) => a.Id == b.Id);
}
关键是,并不是所有的Ts都具有Id属性,有些将具有不同的名称,有些将具有复合键。原始的
AssertReadWorks()
如果不是泛型的,则可以正常工作。问题只是在泛型情况下动态构建谓词。如果它可以用不同于keyComparer参数的东西来完成,我可以


有什么想法吗?:)

如果我错了,请纠正我,但此函数的全部目的是检查相等性吗?要在一般意义上做到这一点,您可以使用。这样,您的对象就知道如何将自己与同一对象进行比较。这将减少代码重用,并有助于避免在多个位置创建相同的表达式

所以你的班级看起来是这样的:

public class DataFieldSet : IEquatable<DataFieldSet>
{
    public int Id { get; set; }

    public bool Equals(DataFieldSet other)
    {
        return other != null && this.Id == other.Id;
    }
}
公共类数据字段集:IEquatable
{
公共int Id{get;set;}
公共布尔等于(数据字段集其他)
{
返回other!=null&&this.Id==other.Id;
}
}
还有你的断言函数

public void AssertReadWorks<T>(
    IRepository<T> repository, 
    T entity) where T : IEquatable<T>
{
    entity = repository.GetAll().Single(x => entity.Equals(x);
}
public void资产readworks(
i存储库,
T实体)其中T:i可满足
{
entity=repository.GetAll().Single(x=>entity.Equals(x);
}

检查是否适合您

public T AssertReadWorks<T>(
    IRepository<T> repository,
    Func<T, bool> keyComparer)
{
    return repository.GetAll().Single(keyComparer);
}
公共T资产ReadWorks(
i存储库,
功能键比较器)
{
返回repository.GetAll().Single(keyComparer);
}
使用

[TestMethod]
公开无效证明()
{
var repository=newrepository(new[]{1,2,3});
var强度=3;
AssertReadWorks(存储库,e=>e==intEntity);
}
[测试方法]
公共void TestString()
{
var repository=new repository(new[]{“a”、“b”、“c”});
var stringEntity=“A”;
AssertReadWorks(repository,e=>string.Equals(e,stringEntity,StringComparison.OrdinalIgnoreCase));
}
[测试方法]
公共void TestThread()
{
var threadEntity=新线程(()=>{});
var repository=new repository(new[]{threadEntity,new Thread(()=>{}),new Thread(()=>{});
AssertReadWorks(存储库,e=>e.ManagedThreadId==threadEntity.ManagedThreadId);
}
编辑: 征求意见的答复:

public void AssertReadWorks<T>(
    IRepository<T> repository,
    ref T entity,
    Func<T, T, bool> keyComparer)
{
    var localEntity = entity;
    entity = repository.GetAll().Single(e => keyComparer(e, localEntity));
}
public void资产readworks(
i存储库,
参考T实体,
功能键比较器)
{
var localEntity=实体;
entity=repository.GetAll().Single(e=>keycomarer(e,localEntity));
}

No,这一点并不完全相同。这一点是为了测试从数据库中读取是否按预期工作(主要是为了测试我们的实体框架模型是否正确映射到数据库)。我通过使用where子句或谓词(如果愿意的话)为Single()。在非泛型情况下,它只是变成.Single(x=>x.Id==Entity.Id)如图所示。它非常简单且有效。问题是我需要一个通用版本。这意味着我必须能够比较x和entity的主键(复合键或其他键属性,无论键属性的名称如何)。恐怕这不够通用。我希望AssertReadWorks将该实体作为参数(出于不相关的原因),我希望能够在调用AssertReadWorks的同一行中创建具有new的实体,如图所示。对不起,我认为我毕竟能够使用它。谢谢!唯一的问题是我现在必须使用两行这样的行来调用:var entity=new DataFieldSet{Label=“test”,Title=“test”};AssertCrudOperationsWork(entity,x=>x.Id==entity.Id,x=>x.IsClosed=true);理想情况下,我希望能够调用AssertCrudOperationsWork()在一行中,在同一行中新建实体,然后在同一行中新建实体,提供测试键相等性的方法。但这总比什么都没有好。如果我使用您编辑的响应,我必须将调用者处的keyComparer参数更改为类似(a,b)的值=>a.Id==b.Id这很好,但是调用Single会引发这样的问题:LINQ to Entities中不支持LINQ表达式节点类型“Invoke”。@pinkfloydhomer抱歉,忘记了您有LINQ2Entities。我想我们已经解决了这个问题,但我缺乏实现它的知识。所以我发布了我自己的问题:))我不理解您使用
实体
参数的方式。由于只更改局部变量,因此在方法之外无法访问检索到的实体。我认为你应该让你的方法返回实体。还有,这有什么不同?我不需要方法之外的实体内容。我只需要测试是否可以从存储库中读取具有相同Id的实体。这与我之前的问题不同,因为这是一种不同的方法,也是一个更简单的示例。
[TestMethod]
public void TestInt()
{
    var repository = new Repository<int>( new[] {1, 2, 3} );
    var intEntity = 3;
    AssertReadWorks(repository, e => e == intEntity);
}

[TestMethod]
public void TestString()
{
    var repository = new Repository<string>(new[] { "a", "b", "c" });
    var stringEntity = "A";
    AssertReadWorks(repository, e => string.Equals(e, stringEntity, StringComparison.OrdinalIgnoreCase));
}

[TestMethod]
public void TestThread()
{
    var threadEntity = new Thread(() => { });
    var repository = new Repository<Thread>(new[] { threadEntity, new Thread(() => { }), new Thread(() => { }) });
    AssertReadWorks(repository, e => e.ManagedThreadId == threadEntity.ManagedThreadId);
}
public void AssertReadWorks<T>(
    IRepository<T> repository,
    ref T entity,
    Func<T, T, bool> keyComparer)
{
    var localEntity = entity;
    entity = repository.GetAll().Single(e => keyComparer(e, localEntity));
}