包含实体框架的通用Find()

时间:2012-07-25 18:23:29

标签: c# entity-framework generics

我目前有一个完整的通用存储库,但我缺少一个功能,那就是使用 包括()Find()在一起。

所以现在我有:

public E FindById<E>(int id) where E : class
{
    return DataContext.Set<E>().Find(id);
}

使用

调用
var person = PersonRepo.FindById<Person>(personId);

我想要有类似的东西:

var person = PersonRepo.FindByIdWithIncludes<Person>(personId,new[]{"State.Address"});

所以,沿着这条路线(这只是一个测试):

public E FindByIdWithIncludes<E>(int id, string[] includes) where E : class
{
    var entitySet = DataContext.Set<E>();
    DbQuery<E> entityQuery;

    foreach (var include in includes)
    {
        entityQuery = entitySet.Include(include);
    }

    return entityQuery.Find(id); //this is were it breaks
}

有可能吗?

2 个答案:

答案 0 :(得分:7)

您无法直接使用Find - Find无法使用包含。您必须使用SingleOrDefault

首先,您需要为实体定义接口以公开其密钥。

public interface IEntityWithId 
{
    public int Id { get; set; }
}

接下来,您可以编写带约束的简单方法来访问密钥:

public E FindByIdWithIncludes<E>(int id, string[] includes) 
    where E : class, IEntityWithId
{          

    IQueryable<E> entityQuery = DataContext.Set<E>();

    foreach (var include in includes)
    {
            entityQuery = entityQuery.Include(include);
    }

    return entityQuery.SingleOrDefault(e => e.Id == id); 
}

顺便说一下。您可以使用强类型包含 - here is an example

答案 1 :(得分:2)

你可以反过来使用Find,但与Load结合使用。在某些情况下,表现可能比Include-SingleOrDefault更好,但这实际上取决于情景。

非通用示例:

 private User GetByUID(int uID, bool includeDetails = false, bool includeAddresses = false)
 {
    var result = context.Users.Find(uID);
    if (includeDetails)
    {
       // load user-details (1:1 relation)
       context.Entry(result)
              .Reference<UserDetails>(us => us.UserDetails)
              .Load();
    }
    if (includeAddresses) 
    {
       // load user-addresses (1:m relation)
       context.Entry(result)
              .Collection(us => us.Addresses)
              .Load();    
    }
    return result;
 }

根据您的需要制作它是不应该的。