【问题标题】:EF4.1 (Database First) Generic Repository: Problem with inconsistent data typesEF4.1(数据库优先)通用存储库:数据类型不一致的问题
【发布时间】:2011-08-26 14:00:19
【问题描述】:

我正在开发一个使用旧系统数据库的新应用程序。数据库中的每个表(大约有 600 个)都有一个“已删除”列来标记该项目是否应显示给用户。在我的通用存储库中,我需要添加 LINQ 表达式来过滤掉所有带有 Deleted == 1/True 的项目。

我遇到的问题是“已删除”列在表中具有不同的数据类型。

它是任何给定表中的 tinyint、smallint 或 bit。从理论上讲,这应该不是什么大问题,因为数据将始终存储为 1 或 0(嗯,应该是,我想,但无论哪种方式都是某种数字),它们可以转换为任何特定的上面提到的类型。我只是不确定如何和/或在哪里进行投射。

我创建了一个接口,它强制所有实体公开此属性,但由于类型不同,每个具有不同数据类型的实体都会导致问题。我希望(尽管已经知道它不起作用)我可以将接口更改为“对象”或“动态”,这仍然会导致编译时错误,因为 EDMX 模型正在创建数据模型类。如果这不能解决问题,我不想花太多时间在 T4 模板中编写代码。

当我将 EDMX 模型的实体属性更改为遵循特定数据类型时,我收到映射错误(“成员映射特定无效。成员 'Deleted' 的类型 'Edm.Byte[]' in type 'MyEntity' 与 'SqlServer.bit[]' 不兼容 ....)

我怀疑我是否能够更改表中的数据类型,因为有许多不同的应用程序使用这个数据库,我相信它会在某个地方引起问题。

有没有其他人遇到过类似的情况并提出了可行的解决方案?

[编辑] 我将采用 Baldy 推荐的解决方案,并创建一个视图来包装表格并创建一个附加列,该列将用于将列转换为位。

【问题讨论】:

    标签: generics repository-pattern entity-framework-4.1


    【解决方案1】:

    您可能需要考虑使用 T-SQL 脚本转换表上的实际字段的临时任务。

    你考虑过吗?你有什么理由做不到吗?

    这可能被证明是一个很好的举措......

    【讨论】:

    • 我已经想到了,但是正如我在原帖中提到的,目前使用这个数据库的应用程序太多了。对数据库的任何更改都可能导致我目前甚至不知道的应用程序出现问题。我们正在寻求解决所有这些问题并进行长期迁移,但目前,我们必须尽可能不考虑这个数据库。
    • 如何将每个表包装在一个视图中并在那里执行转换?从 table1 中选择 *, cast(fieldx as bit) as [castedToBool]。仍有大量工作要做,但可行的解决方法。
    • 我认为这是最简单的解决方案,但我没有想到这一点很失望。这种变化不会影响任何东西,并且会为我提供继续工作所需的一切,并且只需很少的努力。非常感谢,我会将此标记为答案。
    【解决方案2】:

    您能否使用读取已删除位并返回统一且一致的值的部分类在每个模型类中创建自定义只读属性?

    【讨论】:

    • 可以这样做,但问题是,我无法访问 Linq-To-Sql 语句中的自定义属性。换句话说,我必须从数据库中检索所有需要的记录,然后执行内存过滤。不过感谢您的想法。
    【解决方案3】:

    通用方法基于您的实体具有相同行为这一事实。在您的情况下,这意味着具有相同类型的相同属性。您的实体不满足此要求,因此您不能使用通用方法。

    您必须以某种方式注入通用行为。这个呢:

    public interface IDeletable<TVal> where TVal : struct
    {
        TVal Deleted { get; set; }
    }
    
    public class Entity : IDeletable<bool>
    {
        public bool Deleted { get; set; }
        ...
    }
    
    public interface IDeletingStrategy<TEntity, TVal> 
        where TEntity : class, IDeletable<TVal>
        where TVal : struct
    {
        void Delete(TEntity entity);
        IQueryable<TEntity> GetActive(IQueryable<TEntity> query);
    }
    
    public class Repository<TEntity, TVal> 
        where TEntity : class, IDeletable<TVal>
        where TVal : struct
    {
       private IDeletingStrategy<TEntity,TVal> _deletingStrategy;
    
       public Repository(IDeletingStrategy<TEntity, TVal> deletingStrategy)
       {
           _deletingStrategy = deletingStrategy;
       }
    
       public void Delete(TEntity entity)
       {
           _deletingStrategy.Delete(entity);
           ...
       }
    
       public IQueryable<TEntity> GetActive()
       {
           return _deletingStrategy.GetActive(context.Set<TEntity>());
       }
    
    }
    
    public class BoolDeletingStrategy<TEntity> : IDeletingStrategy<TEntity, bool>
        where TEntity : class, IDeletable<bool>
    {
        public void Delete(TEntity entity)
        {
            entity.Deleted = true;
        }
    
        public IQueryable<TEntity> GetActive(IQueryable<TEntity> query)
        {
            return query.Where(e => !e.Deleted);
        }
    }
    

    您将像这样实例化您的存储库:

    var repo = new Repository<Entity, bool>(new BoolDeletingStrategy<Entity>());
    

    我没有测试它,但我想它可以工作。

    【讨论】:

    • 嗯,这是个好主意。我可能不得不玩这个。理论上它肯定可以工作,唯一的问题是我将在 T4 模板中添加它,所以我需要一种方法来找出传递给 IDeletable 接口的内容。不过好主意,我会试一试......如果这需要太多时间,我可能不得不求助于添加一些新列作为位类型并创建触发器,或者使用计算值做一些事情。感谢您的想法!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-11
    • 1970-01-01
    • 2014-07-20
    • 2020-02-21
    • 1970-01-01
    相关资源
    最近更新 更多