泛型方法是否可以返回我指定的属性

本文关键字:属性 返回 是否 泛型方法 | 更新日期: 2023-09-27 18:00:53

昨天Ognyan帮我写了很多方法:

public static class DbSetExtensions
{
    public static T AddIfNotExists<T>(this DbSet<T> dbSet, T entity, Expression<Func<T, bool>> predicate = null) where T : class, new()
    {
        var exists = predicate != null ? dbSet.Any(predicate) : dbSet.Any();
        return !exists ? dbSet.Add(entity) : null;
    }
}

当这对我的实体进行Add时,我会返回实体的新ID,但如果它存在,则返回null。

有时我想取回已经存在的实体的ID。但是,我的实体的Key ID属性将根据模型的不同而有所不同。例如,Address模型的键是AddressId,Profile的键是ProfileId。

因此,我想修改这个查询(或制作它的另一个版本(,以接受Id属性名称作为参数。(或者使用EF来识别主键。(然后做这样的事情:

public static class DbSetExtensions
{
    public static T AddIfNotExists<T>(this DbSet<T> dbSet,  
        T entity,  
        Expression<Func<T, bool>> predicate = null,  
        Expression<Func<T, TId>> keyColumnName) where T : class, new()
    {
        var exists = predicate != null ? dbSet.Where(predicate).Select(e => e.keyColumnName) : dbSet.Any();
        return !exists ? dbSet.Add(entity) : exists ;
    }
}

我不确定这是否是定义我想要使用的属性的正确方式。我也意识到这可能没有只做Any((那么快,但有时我们可能需要获得ID。

我也想更好地理解所有这些项目的含义以及它们是如何协同工作的。我到处都是,弄得零零星星,但还没能把整个谜题拼在一起。

泛型方法是否可以返回我指定的属性

也许有更好的解决方案,但你可以尝试一下:

   public static TResult AddIfNotExists<T,TResult>(this DbSet<T> dbSet,  
                                                   T entity, 
                                                   Expression<Func<T, bool>> predicate,
                                                   Expression<Func<T, TResult>> columns  
                                                  ) where T : class, new()
   {
       if (predicate==null || columns==null)
           throw new Exception();
       //Find if already exist the entity and select its key column(s)
       var result =  dbSet.Where(predicate).Select(columns).FirstOrDefault();
       //the result could be a reference type (string or anonymous type) or a value type
       if (result!=null && !result.Equals(default(TResult)))
           return result;
       var newElement = dbSet.Add(entity);
       //Compile the Expresion to get the Func
       var func = columns.Compile();
       //To select the new element key(s), add the element to an array (or List) to apply the Select method and get the keys
       var r = new[]{newElement};
       return r.Select(func).FirstOrDefault();
   }

正如你所看到的,我总是希望参数predicate检查元素是否已经存在,columns选择键,以防你有一个具有复合PK的实体(但请注意,你可以从该实体中选择你想要的所有属性,而不仅仅是键(。然后,我应用表达式进行筛选,并在元素存在的情况下选择键。如果它不存在,我会将实体添加到它的DbSet<T>中,但存在问题。如何获取新元素密钥?好吧,我找到的唯一解决方案是将该元素添加到数组中,编译表达式以获得Func<T,TResult>,并将该Func<T,TResult>应用于数组,(我知道这可能不是最好的解决方案,但它应该有效(。

例如,要为具有复合PK的实体调用此扩展方法,可以执行以下操作:

.AddIfNotExists(element, e => e.UserName== "admin", e => new{ e.Id1,e.Id2});

您的情况应该更简单:

public static class DbSetExtensions
{
    public static T AddIfNotExists<T>(this DbSet<T> dbSet, T entity,
        Expression<Func<T, bool>> predicate = null) where T : class, new()
    {
        T exists = predicate != null ?
            dbSet.Where(predicate).FirstOrDefault():
            dbSet.FirstOrDefault();
        return exists == null ?
            dbSet.Add(entity):
            exists;
    }
}

然后,正如您似乎知道PK属性一样,您可以从返回的值中检查它。