Kab*_*5CZ 6 c# valueconverter linq-to-sql entity-framework-core
我正在使用Microsoft的Entity Framework Core并尝试使用ValueConverters来允许我的数据库模型实体中的自定义类型.关键是要拥有自己的类型,我可以自定义,并将其余代码与数据库中实际使用的类型屏蔽开来.
(遗憾的是,遗留代码直接访问模型实体而没有接口,所以除非我进行重大改造,否则这就是我剩下的.)
它主要工作,但我的问题是,实体框架不能我喜欢的类型转换为数据库类型的where子句 (可能还有其他,但这是我所遇到的),而是做一个客户端的评价,这显然是一个性能问题,因为所有候选人都被查询.
所以,我想知道是否有人遇到过此问题以及是否有解决方案,或者我是否必须尝试不同的方法.
如果你想要一些代码,那就是.我试图削减它,所以实现有点奇怪,但它仍然以同样的方式失败.
让我们调用我的自定义结构类型ItemId
,让它保存一个字符串,并允许从long或string创建它:
public struct ItemId
{
public string Data;
public ItemId(long data)
{
Data = data.ToString();
}
public ItemId(string data)
{
Data = data;
}
public override bool Equals(object obj)
{
return obj is ItemId itemId && Data == itemId.Data;
}
public override int GetHashCode()
{
return HashCode.Combine(Data);
}
public static bool operator ==(ItemId id1, ItemId id2)
{
return id1.Data == id1.Data;
}
public static bool operator !=(ItemId id1, ItemId id2)
{
return !(id1== id1);
}
}
Run Code Online (Sandbox Code Playgroud)
然后,我的转换器用于存储64位数字ID的数据库.我强烈怀疑手写的表达式是不必要的,因为内置转换器通常不使用它们并且它们似乎工作正常,但我已经添加它们以试图解决我的问题:
public class ItemIdToLongConverter : ValueConverter<ItemId, long>
{
public ItemIdToLongConverter(ConverterMappingHints mappingHints = null)
: base(ToLong(), ToItemId(), mappingHints)
{ }
protected static Expression<Func<ItemId, long>> ToLong()
{
var data = typeof(ItemId).GetField(nameof(ItemId.StringData));
var tryParseMethod = typeof(long).GetMethod(
nameof(long.TryParse),
new[] { typeof(string), typeof(NumberStyles), typeof(IFormatProvider), typeof(long).MakeByRefType() });
var param = Expression.Parameter(typeof(ItemId));
var parsedVariable = Expression.Variable(typeof(long));
return Expression.Lambda<Func<ItemId, long>>(
Expression.Block(
typeof(long),
new[] { parsedVariable },
Expression.Condition(
Expression.Call(
tryParseMethod,
Expression.Field(param, data),
Expression.Constant(NumberStyles.Any),
Expression.Constant(CultureInfo.InvariantCulture, typeof(IFormatProvider)),
parsedVariable),
parsedVariable,
Expression.Constant(default(long), typeof(long)))),
param);
}
protected static Expression<Func<long, ItemId>> ToItemId()
{
var ctor = typeof(ItemId).GetConstructor(new[] { typeof(long) });
var param = Expression.Parameter(typeof(long));
return Expression.Lambda<Func<long, ItemId>>(
Expression.Block(
typeof(ItemId),
Expression.New(ctor, param)
),
param);
}
}
Run Code Online (Sandbox Code Playgroud)
我以这种方式在模型中注册我的转换器:
modelBuilder.Entity<MyTable>(entity =>
{
...
entity.Property(e => e.ItemId).HasConversion(new ItemIdToLongConverter()).ValueGeneratedNever();
...
});
Run Code Online (Sandbox Code Playgroud)
这是一个得到客户端评估的查询,因为它无法转换id
为数据库类型:
var id = new ItemId(100);
dbContext.MyTable.FirstOrDefault(x => x.ItemId == id);
Run Code Online (Sandbox Code Playgroud)
奇怪的是,这个奇怪结构的一个被翻译得很好:
var ids = Enumerable.Repeat(new ItemId(100), 1);
dbContext.MyTable.FirstOrDefault(x => ids.Contains(x.ItemId));
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
500 次 |
最近记录: |