EF同样适用于不同的对象

时间:2013-10-02 09:07:58

标签: c# entity-framework linq-to-entities

请看下面的句子:

 class CompanyDto  {
     public string Street { get; set;}
     public int Number { get; set;}
     public bool IsAttr1 { get; set;}
     public bool IsAttr2 { get; set;}
     public bool IsAttr3 { get; set;}
     // Other not common Properties
 }

 class AnimalDto {
     public string Street { get; set;}
     public int Number { get; set;}
     // Other not common Properties
 }

 class HouseDto {
     public bool IsAttr1 { get; set;}
     public bool IsAttr2 { get; set;}
     public bool IsAttr3 { get; set;}
     // Other not common Properties
 }

 class PersonDto {
     public string Street { get; set;}
     public int Number { get; set;}
     public bool IsAttr1 { get; set;}
     public bool IsAttr2 { get; set;}
     public bool IsAttr3 { get; set;}
     // Other not common Properties
 }

我想要从Entinty Framework上下文中填充这些Dtos。我想用标准where子句过滤结果。 例如:

 List<PersonDto> prs = context.Person.Where(x => x.Number == SomeValue && Street == SomeOtherValue).Where( x=> x.IsAttr1 || x.IsAttr2).Select(//projection here).ToList();

 List<AnimalDto> anmls = context.Animal.Where(x => x.Number == SomeValue && Street == SomeOtherValue).Select(//projection here).ToList();

 etc.

我想将它们投射到Dtos(简单),但我不想一次又一次地写Where子句。我尝试使用extention方法做到这一点,但在使用基类(Address和Flags)和使用Interfaces时都失败了,因为IQuerable不能从Interface转换为Concrete类。

我有什么方法可以做到这一点吗?

最好的方法是使用这样的扩展方法:

public static IQueryable<IAddress> WhereAddress(this IQueryable<IAddress> qry, int SomeValue, int SomeOtherValue)
    {
        return qry.Where(x => x.Number == SomeValue && Street == SomeOtherValue);
    }

但我无法在WhereAddress子句和IQuerable.cast()之后添加WhereFlags;没有做演员。

2 个答案:

答案 0 :(得分:3)

您可以按如下方式实现扩展方法,并将泛型参数的约束设置为类型IAddressclass这可以避免异常“LINQ to Entities仅支持转换EDM原语或枚举类型“)并在类型CompanyAnimalPerson

上实现界面
public static IQueryable<TAddress> WhereAddress<TAddress>(this IQueryable<TAddress> qry, int SomeValue, string SomeOtherValue)
  where TAddress : class, IAddress {
    return qry.Where(x => x.Number == SomeValue && x.Street == SomeOtherValue);
}

有了这个,你可以打电话

context.Person.WhereAddress(SomeValue,SomeOtherValue).Where(x=> x.IsAttr1 || x.IsAttr2);

但不是

context.House.WhereAddress(SomeValue,SomeOtherValue);

原因House未实施IAddress

答案 1 :(得分:1)

如下:

public IQueryable<T> GetByAddress<T>(DbContext context, int number, string street)
{
    return context.Set<T>().Select<T, IAddress>(x => x.Number == SomeValue && x.Street == SomeOtherValue);  
}

然后在外面你应该能够做到

List<PersonDto> prs = GetByAddress<Person>(context, 1, "1234 Street")
                          .Select(...)
                          .ToList();
List<AnimalDto> anmls = GetByAddress<Animal>(context, 2, "5678 Road")
                          .Select(...)
                          .ToList();

如果您更喜欢扩展方法,那么您应该能够这样做,因为它不会将表格预测到IAddress。 LINQ不支持隐式转换,例如

List<PersonDto> prs = context.Person.Select<Person, IAddress>()
                                    .WhereAddress(1, "1234 Street")
                                    .Select(...)
                                    .ToList();
List<PersonDto> prs = context.Animal.Select<Animal, IAddress>()
                                    .WhereAddress(2, "5678 Street")
                                    .Select(...)
                                    .ToList();