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 让我们命名它们:TrueWeirdModel
和 FalseWeirdModel
:
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 查询中的过滤器。使用 TruesWeirdModels
或 FalseWeirdModels
Dbset
时,将自动添加 WeirfBoolean
的 where
过滤器。要获得所有这些,您只需使用摘要 class WeirdModels
DbSet
。因为 WeirdModel
是一个抽象 class 你不能实例化它,如果你想在你的 table 上创建一个新行,你必须使用 FalseWeirdModel
或 TrueWeirdModel
.
我决定使用枚举来表示布尔值
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);
我有一个现有的系统,出于某种原因,我无法理解它在数据库中的负 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 让我们命名它们:TrueWeirdModel
和 FalseWeirdModel
:
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 查询中的过滤器。使用 TruesWeirdModels
或 FalseWeirdModels
Dbset
时,将自动添加 WeirfBoolean
的 where
过滤器。要获得所有这些,您只需使用摘要 class WeirdModels
DbSet
。因为 WeirdModel
是一个抽象 class 你不能实例化它,如果你想在你的 table 上创建一个新行,你必须使用 FalseWeirdModel
或 TrueWeirdModel
.
我决定使用枚举来表示布尔值
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);