通用存储库模式IEntity属性区分大小写

时间:2015-02-16 13:29:05

标签: c# asp.net-mvc design-patterns repository-pattern

我在我的应用程序中使用Generic Repository Pattern。我正在尝试这篇文章http://www.remondo.net/repository-pattern-example-csharp/。问题是,数据库代码生成工具(代码首先来自现有数据库)生成以下模型:

[Table("TableName1")]
public partial class TableName1 : IEntity
{
    public int ID { get; set; }

    [StringLength(50)]
    public string Name { get; set; }

    ::::::::
}

[Table("TableName2")]
public partial class TableName2 : IEntity
{
    public int Id { get; set; }

    [StringLength(50)]
    public string Name { get; set; }

    ::::::::
}

我刚刚在上面的数据库模型中应用了IEntity,但是TableName2类存在问题,因为IEntity接口的“ID”属性不是“Id”。这是一个

public interface IEntity
{
    int ID { get; }
}

那么如何在不查看案例的情况下将此IEntity转换为接受属性?如果我不想为每个表创建单独的独立新模型,我需要最简单的解决方案吗?

2 个答案:

答案 0 :(得分:2)

我正在使用的方法现在被实体框架本身克服,不确定哪个版本的实体框架。下面的代码显示了实体框架的通用存储库模式的一个漂亮而干净的实现。这里不需要IEntity接口,因为我们使用DbSet类的方便的Find扩展方法。

所以这是IRepository:

public interface IRepository<T>
{
    void Insert(T entity);
    void Delete(T entity);
    IQueryable<T> SearchFor(Expression<Func<T, bool>> predicate);
    IQueryable<T> GetAll();
    T GetById(int id);
}

这是存储库:

public class Repository<T> : IRepository<T> where T : class
{
    protected DbSet<T> DbSet;

    public Repository(DbContext dataContext)
    {
        DbSet = dataContext.Set<T>();
    }

    #region IRepository<T> Members

    public void Insert(T entity)
    {
        DbSet.Add(entity);
    }

    public void Delete(T entity)
    {
        DbSet.Remove(entity);
    }

    public IQueryable<T> SearchFor(Expression<Func<T, bool>> predicate)
    {
        return DbSet.Where(predicate);
    }

    public IQueryable<T> GetAll()
    {
        return DbSet;
    }

    public T GetById(int id)
    {
        return DbSet.Find(id);
    }

    #endregion
}

将实体框架代码保留为第一个代码。现在,我们已准备好在应用程序中使用此通用存储库,具体如下:

using (var dataContext = new UserBaseContext())
{
    var userRepository = new Repository<Users>(dataContext);

    Users user = userRepository
        .SearchFor(c => c.Name.StartsWith("A"))
        .Single();

    //do other stuff

}

这不会抱怨套管等等,很高兴我有我的第一个工作通用存储库:)

答案 1 :(得分:1)

如果您正在使用代码优先方法,Entity Framework将在生成表时自动复数您的实体名称,因此我们首先为您的问题添加一些上下文并删除所有抽象,假设我们正在创建一个用户存储库,实体框架将自动生成Users表。

public partial class User : IEntity
{
    public int Id { get; set; }

    [StringLength(50)]
    public string Name { get; set; }
}

public partial class BlogPost : IEntity
{
    public int Id { get; set; }

    [StringLength(50)]
    public string Title { get; set; }
}

public interface IEntity
{
    int Id { get; }
}

没有办法绕过套管规则,这是一个规则,并且尽管我们喜欢成为牛仔,你写的东西甚至不能编译为interface合同即可。如果class实施合同,则必须实施合同概述的所有内容;属性Id,至少有getter

我看了一下你提供的链接,它没有告诉你的是你应该如何正确实现IRepository,你的每个实体应该有自己的存储库,我会修改那个接口这样做:

public interface IRepository<T> where T : class, IEntity
{
    void Insert(T entity);
    void Delete(T entity);
    IQueryable<T> SearchFor(Expression<Func<T, bool>> predicate);
    IQueryable<T> GetAll();
    T GetById(int id);
}

我们在此处所做的是,我们已经说过IRepository将与任何实现IRepository接受实现type parameter合同的IEntity的存储库一起使用。

public class UserRepository<User> : IRepository<User>
{ 
    protected Table<User> DataTable;

    public Repository(DataContext dataContext)
    {
        DataTable = dataContext.GetTable<User>();
    }

    #region IRepository<T> Members

    public void Insert(User entity)
    {
        DataTable.InsertOnSubmit(entity);
    }

    public void Delete(User entity)
    {
        DataTable.DeleteOnSubmit(entity);
    }

    public IQueryable<User> SearchFor(Expression<Func<User, bool>> predicate)
    {
        return DataTable.Where(predicate);
    }

    public IQueryable<User> GetAll()
    {
        return DataTable;
    }

    public User GetById(int id)
    {
        // Sidenote: the == operator throws NotSupported Exception!
        // 'The Mapping of Interface Member is not supported'
        // Use .Equals() instead
        return DataTable.Single(e => e.Id.Equals(id));
    }

    #endregion
}