【问题标题】:Generic Find() with Includes Entity Framework包含实体框架的通用 Find()
【发布时间】:2012-07-25 18:23:28
【问题描述】:

我目前有一个完整的通用存储库,但我缺少一个功能,那就是使用 Include()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
}

有可能吗?

【问题讨论】:

    标签: c# entity-framework generics


    【解决方案1】:

    您不能直接使用 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

    【讨论】:

    • 我很感兴趣,如果没有命名的 Id 而是 [TableName]Id,您将如何公开实体键?我已经实现了强类型包含,因为我在研究我的问题时发现了你的帖子。问候
    • 我之前回答过 ObjectContext 的类似问题 - 您只需要将 DbContext 转换为 ObjectContext:检查 this onemore complex one 但如果您使用相同的键名,您只会帮助自己很多和界面。
    • 谢谢。我使用相同的键名,但我目前正在处理的数据库搞砸了。问候
    【解决方案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;
     }
    

    根据您的需求使其通用化应该不难。

    【讨论】:

    • 如果我错了,请纠正我,但这会导致向服务器发送多个查询。 Include OTOH 将允许通过简单的查询获取所有数据。因此,尽管此解决方案有效,但重要的是要了解它可能并不总是适合替代 Include 扩展。
    猜你喜欢
    • 2011-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-06
    • 1970-01-01
    • 1970-01-01
    • 2023-03-07
    • 1970-01-01
    相关资源
    最近更新 更多