Entity Framework 6 - 将负数 1 映射到 C# true

Entity Framework 6 - Mapping negative 1 to C# true

我有一个现有的系统,出于某种原因,我无法理解它在数据库中的负 1 (-1) 作为 true 的表示形式 (Oracle 12.C)

我真的很希望能够在 EF 6 中将其映射到一个布尔值,而无需进行包装 属性。

有人知道支持这种情况的方法吗?我看到的问题是,像 Where(v => !v.IsDeleted) 这样的 linq 查询将生成 SQL,这是正 1 导向的,即 WHERE (item.IS_DELETED <> 1))

如果我能让生成的 SQL 对与 false(零值)的关系更感兴趣,那么我就可以让我的 C# 代码不可知

任何帮助或指点将不胜感激!

我将利用 TPH(Table 每个层次结构) ORM 模式与 EF。使用此模式,您的所有基础 class 和派生 classes 将共享相同的 table。 table 的每一行将由鉴别器区分。

首先我要有这个摘要class所以我们把它命名为WeirdModel:

public abstract class WeirdModel
{
    public int Id { get; set; }
    public string SomeProperty { get; set; }
}

然后从 WeirdModel 创建两个派生的 classes 让我们命名它们:TrueWeirdModelFalseWeirdModel:

public class TrueWeirdModel : WeirdModel
{
}

public class FalseWeirdModel : WeirdModel
{
}

我的上下文定义如下:

public class MyContext : DbContext
{
    public DbSet<WeirdModel> Weirds { get; set; }
    public DbSet<FalseWeirdModel> FalseWeirdModels { get; set; }
    public DbSet<TrueWeirdModel> TrueWeirdModels { get; set; }

    public MyContext()
        : base("MyContext")
    {
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<WeirdModel>()
            .Map<TrueWeirdModel>(p => p.Requires("WeirdBoolean").HasValue(-1))
            .Map<FalseWeirdModel>(p => p.Requires("WeirdBoolean").HasValue(1));
    }
}

这里我说 DB 上的 WeirdBoolean 列将包含

  • -1 对于 TrueWeirdModel
  • 1 对于 FalseWeirdModel

要使用它们:

using (var context = new MyContext())
{
    var trueWeirdData = new TrueWeirdModel { SomeProperty = "true weird model" };
    var falseWeirdData = new FalseWeirdModel { SomeProperty = "false weird model" };

    context.Weirds.AddRange(new WeirdModel[] { trueWeirdData, falseWeirdData });

    context.SaveChanges();
}

using (var context = new MyContext())
{
    var allWeirdModels = context.Weirds.ToList();

    var allTrueWeirdData = context.TrueWeirdModels.ToList();

    var allFalseWeidData = context.FalseWeirdModels.ToList();
}

在您的数据库中,我们将拥有:

使用 TPH ORM 模式,您将永远不会操纵用作鉴别器的怪异列 WeirdBoolean。顺便说一句,您仍然可以创建一个映射到它的 属性。

在您的整个应用程序中,您永远不必将此列用作 Linq To Entities 查询中的过滤器。使用 TruesWeirdModelsFalseWeirdModels Dbset 时,将自动添加 WeirfBooleanwhere 过滤器。要获得所有这些,您只需使用摘要 class WeirdModels DbSet。因为 WeirdModel 是一个抽象 class 你不能实例化它,如果你想在你的 table 上创建一个新行,你必须使用 FalseWeirdModelTrueWeirdModel .

我决定使用枚举来表示布尔值

public enum BooleanType
{
    False = 0,
    True = -1
}

由于 EF 没有正确支持枚举属性(它将在 ORACLE 中转换) 然后我添加了一个 Linq 扩展方法来删除不必要的转换。

public class RemoveCastVisitor : ExpressionVisitor
{
    protected override Expression VisitBinary(BinaryExpression node)
    {
        if (node.NodeType == ExpressionType.Equal) {
            var leftUnary = node.Left as UnaryExpression;
            var rightUnary = node.Right as UnaryExpression;

            if (leftUnary == Null || rightUnary == Null)
                return base.VisitBinary(node);

            if (leftUnary.NodeType != ExpressionType.Convert)
                return base.VisitBinary(node);

            if (rightUnary.NodeType != ExpressionType.Convert)
                return base.VisitBinary(node);

            return Expression.Equal(leftUnary.Operand, rightUnary.Operand);
        }
        return base.VisitBinary(node);
    }
}


public static class QueryableExtensions
{
    /// <summary>
    /// Removes ANY Casting from the Query Expression
    /// </summary>
    public static IQueryable<T> RemoveCasts<T>(this IQueryable<T> q)
    {
        var visitor = new RemoveCastVisitor();
        Expression original = q.Expression;
        var expr = visitor.Visit(original);
        return q.Provider.CreateQuery<T>(expr);
    }
}

这是我的测试,显示它有效

IQueryable<int> query = context.Set<UnitTest>().Where(v => v.IsDeleted == BooleanType.True).Select(v => v.Id);
query = query.RemoveCasts();
var sql = ((DbQuery<int>)query).ToString();

var expected =
    "SELECT \r\n" +
    "\"Extent1\".\"ID\" AS \"ID\"\r\n" +
    "FROM \"EZIAUS\".\"ZZ_UNIT_TEST\" \"Extent1\"\r\n" +
    "WHERE (-1 = \"Extent1\".\"IsDeleted\")";

Assert.AreEqual(expected, sql);