代码之家  ›  专栏  ›  技术社区  ›  Hafeez Khan

主键属性名称在通用存储库模式中不同

  •  2
  • Hafeez Khan  · 技术社区  · 7 年前

    我在数据库中有多个表,每个表的主键都很长,id列名不是泛型的,即每个表的主键列名都不同。

    • Customer 主键为“CustomerId”
    • Employee 主键为'EmployeeId'

    在域模型类中表示相同的对象

    class Customer { public long CustomerId { get; set; } 
    
    class Employee { public long EmployeeId { get; set; }
    

    public async Task<TEntity> GetById(int id)
    {
        return await _dbContext.Set<TEntity>()
                    .AsNoTracking()
                    .FirstOrDefaultAsync(e => e.**Id** == id);
    }
    

    Id CustomerId EmployeeId

    3 回复  |  直到 7 年前
        1
  •  2
  •   Classe    7 年前

    根据实际需要,我会考虑将类中的属性重命名为Id,然后将它们映射到模型配置中数据库中的键:

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<MyEntityType>().Property(k => k.Id).HasColumnName("CustomerId");
    
    // ...
    }
    

    但是,如果您真的想坚持使用这些属性,并且仍然想使用泛型方法来获取它们(天知道为什么),那么您可能必须在某个接口上公开一个func,以便稍后用于比较。

    也许是这样的:

            // An interface that requires a func to match it's id
            public interface IExpressionKeyEntity
            {
                // A func that takes an int and returns true if it's a match
                // against the entity id
                Func<int, bool> HasMatchingId { get; }
            }
    

            // A simple customer class that implements the interface
            public class Customer : IExpressionKeyEntity
            {
                // An id property that we don't know anything about from the outside
                public int CustomerId { get; set; }
    
                // A func that takes an id and returns true if it's a match against this entities id
                public Func<int, bool> HasMatchingId => comparisonEntityId => comparisonEntityId == CustomerId;
            }
    

    然后对GetById方法进行一些小的更改:

                // GetById now requires an IExpressionKeyEntity to be retrieved
                public async Task<TEntity> GetById<TEntity>(int id)
                    where TEntity : IExpressionKeyEntity
                {
                    // Return the first match based on our func
                    return await _dbContext.Set<TEntity>()
                        .AsNoTracking()
                        .FirstOrDefault(q => q.HasMatchingId(id));
                }
    

        2
  •  1
  •   hawkstrider    7 年前

    所以使用这种通用模式,你的逻辑有点缺陷。如果没有属性和反射,您将无法从TEntity类型确定主id字段的名称。更好的办法是让实体实现一个接口,然后在泛型上设置一个约束。沿着这条线的东西

    public interface IEntity {
        int id {get;set;}
    }
    
    public class Customer : IEntity {
        public int id {get; set;}
    }
    

    然后在存储库中,可以将泛型约束到IEntity类型。 这将允许您仅基于id字段查询任何IEntity类型。

    where TEntity: IEntity
    

    public async Task<TEntity> GetById(int id)
    {
        //Since TEntity is an IEntity, it is guaranteed to have an id property
        return await _dbContext.Set<TEntity>()
                    .AsNoTracking()
                    .FirstOrDefaultAsync(e => e.Id == id);
    }
    
        3
  •  0
  •   Monolith Mehul Kabaria    7 年前

    不过,我的心安放在一边。如果你有标准化的Id命名,你可以使用一个接口

    public interface IId
    {
        public long Id {get;set;}        
    }
    
    // ...
    
    class Customer : IId { public long ID{get;set;} ...}
    class Employee : IId { public long ID{get;set;} ...}
    
    public async Task<TEntity> GetById<TEntity>(int id) where TEntity : IId
    {
        return await _dbContext.Set<TEntity>()
                    .AsNoTracking()
                    .FirstOrDefaultAsync(e => e.Id == id);
    }
    

    public static async Task<T> GetById<T>(this IQueryable<T> entities, Expression<Func<T, long>> propertySelector, long id)
    {
       var member = propertySelector.Body as MemberExpression;
    
       var property = member.Member as PropertyInfo;
       var parameter = Expression.Parameter(typeof(T));
    
       var expression = Expression.Lambda<Func<T, bool>>(Expression.Equal(Expression.Constant(id), Expression.Property(parameter, property)), parameter);
    
       return await entities.FirstOrDefaultAsync(expression);
    }
    

    免责声明 ,所有这些都是完全未经测试的,没有错误检查